Django ORM: правильная организация огромных объемов данных - PullRequest
1 голос
/ 23 ноября 2010

У меня есть приложение Django, которое использует django-поршень для отправки XML-каналов внутренним клиентам.Как правило, они работают довольно хорошо, но у нас есть несколько XML-каналов, которые в настоящее время работают более 15 минут.Это приводит к превышению времени ожидания, и каналы становятся ненадежными.

Я пытаюсь обдумать, как можно улучшить эту настройку.Если это требует некоторой реструктуризации данных, это тоже возможно.

Вот как выглядит сбор данных в настоящее время:

class Data(models.Model)
     # fields

class MetadataItem(models.Model)
     data = models.ForeignKey(Data)

# handlers.py
data = Data.objects.filter(**kwargs)

for d in data:
   for metaitem in d.metadataitem_set.all():
       # There is usually anywhere between 55 - 95 entries in this loop
       label = metaitem.get_label() # does some formatting here
       data_metadata[label] = metaitem.body

Очевидно, ядро ​​программы делаетгораздо больше, но я просто указываю, где проблема.Когда у нас есть data список из 300, он просто становится ненадежным и время ожидания истекает.

То, что я пробовал:

  • Получение коллекции всех идентификаторов данных, затем выполнениеодин большой запрос, чтобы получить все MetadataItem.Наконец, отфильтровываю те, что в моем цикле.Это должно было сохранить некоторые запросы, которые он уменьшил.
  • Использование .values() для сокращения издержек экземпляра модели, что ускорило его, но не намного.

Oneidea Я думаю, что одним из простых решений этого является пошаговая запись в кэш.Чтобы сократить время ожидания;Я бы написал первые 50 наборов данных, сохранил в кэш, настроил какой-нибудь счетчик, записал следующие 50 и т. Д. Все еще нужно обдумать это.

Ответы [ 4 ]

2 голосов
/ 24 ноября 2010

Проблема в фрагменте кода, который вы опубликовали, состоит в том, что Django не включает объекты, которые автоматически связаны по обратной связи, поэтому вам нужно сделать запрос для каждого объекта. Есть хороший способ обойти это, как отмечает Даниэль Роузман в своем блоге !

Если это не решит вашу проблему, вы также можете попытаться получить все в одном необработанном SQL-запросе ...

1 голос
/ 24 ноября 2010

Возможно, вы могли бы еще больше уменьшить количество запросов, сначала получив все идентификаторы данных, а затем используя select_related, чтобы получить данные и их метаданные в одном большом запросе. Это значительно уменьшит количество запросов, но размер запросов может быть непрактичным / слишком большим. Что-то вроде:

data_ids = Data.objects.filter(**kwargs).values_list('id', flat = True)
for i in data_ids:
    data = Data.objects.get(pk = i).select_related()
    # data.metadataitem_set.all() can now be called without quering the database
    for metaitem in data.metadataitem_set.all():
        # ...

Тем не менее, я бы предложил, если это возможно, предварительно вычислить каналы откуда-то за пределами веб-сервера. Возможно, вы могли бы сохранить результат в memcache, если он меньше 1 МБ. Или вы можете стать одним из самых крутых новых ребят в блоке и сохранить результат в базе данных "NoSQL", такой как redis. Или вы можете просто записать его в файл на диске.

0 голосов
/ 05 декабря 2010

Другая идея заключается в использовании Celery (www.celeryproject.com), который представляет собой систему управления задачами для python и django. Вы можете использовать его для асинхронного выполнения любых длительных задач без необходимости удерживать основной сервер приложений.

0 голосов
/ 24 ноября 2010

Если вы можете изменить структуру данных, может быть, вы также можете изменить хранилище данных?

Базы данных "NoSQL", которые допускают некоторую структуру, такую ​​как CouchDB или MongoDB, на самом деле могут быть полезны здесь.

Допустим, для каждого элемента данных у вас есть документ.Документ будет иметь ваши обычные поля.Вы также добавили бы поле «метаданные», которое представляет собой список метаданных.Как насчет следующей структуры данных:

{
    'id': 'someid',
    'field': 'value',
    'metadata': [
        { 'key': 'value' },
        { 'key': 'value' }
    ]
}

После этого вы сможете легко получить доступ к записи данных и получить все ее метаданные.Для поиска добавьте индексы к полям в документе «data».

Я работал над системой в Erlang / OTP, которая использовала Mnesia, которая в основном является базой данных значений ключей с некоторыми индексами и помощниками.Мы с большим успехом использовали вложенные записи.

Я добавил это как отдельный ответ, так как он полностью отличается от других.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...