2009-12-28 3 views
10

Создайте службу, которая должна поддерживать что-то вдоль линий системы отслеживания случаев. Вот наша модель:Производительность django при запросе моделей со многими внешними ключами?

class Incident(models.Model):  
    title = models.CharField(max_length=128) 
    category = models.ForeignKey(Category) 
    status = models.ForeignKey(Status)  
    severity = models.ForeignKey(Severity) 
    owned_by = models.ForeignKey(User, related_name="owned_by", null=True, blank=True) 
    next_action = models.ForeignKey(IncidentAction)  
    created_date = models.DateTimeField() 
    created_by = models.ForeignKey(User, related_name="opened_by")  
    last_edit_date = models.DateTimeField(null=True, blank=True) 
    last_edit_by = models.ForeignKey(User, related_name="last_edit_by", null=True, blank=True)   
    closed_date = models.DateTimeField(null=True, blank=True) 
    closed_by = models.ForeignKey(User, related_name="Closed by", null=True, blank=True) 

Потому что есть много внешних ключей втянуты в эту модель, она делает для интересных запросов SQL. Мы использовали в качестве пробной версии djblets data grid и панель инструментов отладки django и с тревогой встретили огромное количество запросов, каждый раз добавляя новый столбец для представления, который использует внешний ключ, в основном этот тип рабочего процесса запроса :

#prepare the grid 
select * from incident_table; 
#render each row 
for each row in incident table 
    for each column that is a foreign key select row from foreign table with id 

Это делает дополнительный запрос на выборку в строке для каждого столбца, который пытается тянуть свойство для внешнего ключа.

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

Мы хотим увеличить это, когда тонны пользователей поражают модель. В сравнении с этим я сделал аналогичную точку зрения для модели User, и ее полное отображение просто выполняется с одним запросом, потому что, если вы только вытаскиваете поля из данной модели, это не делает дополнительного удара db за дополнительный столбец.

Некоторые оптимизации мы пытались были:

  • django-orm-cache: Не похоже на работу с Джанго 1.0.4
  • django-caching: Это хорошо работает для кэширования часто запрашивается моделям кэширования уровня
  • вид с memcached
  • Редактировать: Использование select_related() может ускорить отрисовку шаблона, не возвращаясь обратно в базу данных обратно, но похоже, что внешние ключи просто глава времени на исходном запросе с использованием единственного запроса на внешний ключ. Кажется, что переместил запрос на несколько баз данных раньше времени.

Но есть некоторые более глубокие вопросы, мы вымогательство мудрость толпы на:

  • Для моделей с тоннами внешних ключей, что это лучший способ сделать это эффективно запрос, чтобы получить свойства от внешних ключей?
    • Является ли кэширование зависимых моделей единственным способом использования вышеуказанных систем кэширования ORM?
    • Или это стандартный случай перерастания ORM и необходимость свертывания собственного пользовательского sql-запроса с объединениями для получения максимально возможного выходного потока данных?

Похожие вопросы, поднятые проблемы на кэширование и внешних ключей:

DB/performance: layout of django model that rarely refers to its parent more than once, Django ORM: caching and manipulating ForeignKey objects:

ответ

11

select_related() является правильным решением; вы ошибаетесь в том, как он должен работать. Я думаю, что вы не используете select_related правильно, если вы все еще получаете несколько запросов по указанному FK. Быстрый журнал сеанса Python (Студия имеет FK к django.auth.user здесь):

>>> from django.db import connection 
>>> studios = Studio.objects.all().select_related('user') 
>>> for studio in studios: 
>>>  print studio.user.email 
>>>   
[email protected] 
[email protected] 
>>> len(connection.queries) 
1 

Итак, я получил список объектов студии (2 в моей тестовой БД) и получил для каждого пользователя один в одном SQL-запросе. Без вызова select_related() требуется три запроса.

Обратите внимание, что select_related doesn't handle many-to-many relationships - хотя я думаю, что вы можете вручную запросить промежуточную таблицу m2m, чтобы следовать этим FKs в любом направлении, не требуя дополнительного запроса, если вы в порядке, начиная свой запрос от промежуточного объекта. Может быть, это то, что тебя ловит? Вы указали только отношения FK, а не m2ms, поэтому я дал простую иллюстрацию этого.

+0

А, да. Я стою очень исправлен - похоже, что datagrid фактически игнорирует любые оптимизации, предоставляемые поставляемым набором запросов, и выполняет собственные поисковые запросы. Независимое тестирование моей модели с вашим примером сделало преимущества select_related() понятными как день. Благодаря! – dmyung

Смежные вопросы