Оптимизация запросов GQL и архитектура таблиц - PullRequest
0 голосов
/ 03 августа 2010

Я работаю с Google App Engine, и у меня возникают некоторые проблемы с производительностью некоторых моих запросов к данным. Я читал, что проектирование хранилища данных App Engine отличается от работы с базами данных SQL, и я не уверен, что делаю это наилучшим образом. У меня есть два вопроса, чтобы попытаться встать на правильный путь:

В частности:

У меня есть тип Foo и тип UserFoo. Каждый UserFoo является «экземпляром» соответствующего Foo и содержит данные, относящиеся к этому экземпляру. Мой тип Foo имеет свойство fooCode, которое является уникальным идентификатором, и я сопоставляю каждый UserFoo с каждым Foo, используя их свойства fooCode. Затем я оперирую каждым Foo с кодом, подобным следующему:

foos = Foo.all().filter('bar =', bar)
for foo in foos:
    userFoo = UserFoo.all().filter('userKey =', user).filter('fooCode =', foo.fooCode)

Примечание: я использую fooCode поверх ссылочного ключа, чтобы мы могли легко удалять и повторно добавлять новые Foo s, и тогда не нужно будет повторно сопоставлять все соответствующие UserFoo s.

В целом:

Каковы типичные подходы к разработке таблиц хранилища данных GAE и рекомендации по их использованию?

Ответы [ 3 ]

1 голос
/ 04 августа 2010

Это лестница анти-паттерна получает . Решением является Предварительная выборка ReferenceProperty .

Проблема в том, что вы решили не использовать ReferenceProperty. Я бы посоветовал вам пересмотреть этот выбор.

Примечание: я использую fooCode над ссылочный ключ, чтобы мы могли легко удалять и повторно добавлять новые Foos, а не должны затем переназначить все соответствующие UserFoos.

Помните, что ключ сущности - это просто закодированное представление его пути: вид и имя или идентификатор сущности и любых ее предков. Если вы удалили, а затем заново создали Foo, он имел бы другой ключ, только если ему было присвоено другое имя или идентификатор. Если у вас есть какой-то способ присвоения старой и новой сущности одного и того же fooCode, вы можете так же легко использовать fooCode в качестве имени ключа, что позволит удаленному, а затем повторно добавить Foo, чтобы сохранить его исходный ключ.

1 голос
/ 04 августа 2010

Я бы предложил следующие изменения:

  1. Используйте ReferenceProperty в UserFoo для ссылки на его Foo или, если необходимо, сделайте его дочерним объектом. Я не понимаю ваш комментарий о переназначении существующих сущностей - это никогда не должно быть необходимо.
  2. Добавить копию свойства 'bar' для каждого UserFoo
  3. Выполните один запрос для UserFoo.all (). Filter ('bar =', bar) .order ('userKey'). Результаты будут отфильтрованы по столбцу и сгруппированы по пользователю, и для них потребуется только один запрос вместо одного запроса на пользователя.
  4. Получайте результаты сразу, вызывая .fetch () для запроса, а не перебирая их. Это гораздо эффективнее.
  5. Используйте Предварительная выборка ReferenceProperty , чтобы получить объект Foo для каждого UserFoo, если вам это нужно.
1 голос
/ 04 августа 2010

В целом:

  • Максимально денормализовать.

  • При любой возможности обращаться к сущностям через их Ключ;это самый быстрый способ вывести данные из хранилища данных.

В частности, вы, вероятно, могли бы значительно повысить свою производительность, если бы использовали ReferenceProperty для установления отношений, а не кодов, которые входят вфильтры.Я собираюсь догадаться, что запросы к Foo для UserFoo происходят гораздо чаще, чем удаление и переназначение Foo, да?В этом случае прагматичным и мудрым способом для хранения данных является использование ссылочных свойств.

Кроме того, если отношение Foo-UserFoo может быть денормализовано в одну сущность, вы устраняете необходимость в целой сериизапросы в целом.

...