Django Query очень медленный

У меня проблема с приложением Django. Запросы к модели Scope выполняются очень медленно, и после некоторой отладки я так и не понял, в чем проблема.

Когда я запрашиваю базу данных, например scope = Scope.objects.get(pk='Esoterik I'), это занимает от 5 до 10 секунд. В базе данных менее 10 записей и индекс по первичному ключу, поэтому она слишком медленная. При выполнении эквивалентного запроса к базе данных, такого как SELECT * FROM scope WHERE title='Esoterik I';, все в порядке, и это занимает всего около 50 мс.

Та же проблема возникает, если я запрашиваю набор результатов, например scope_list = Scope.objects.filter(members=some_user), а затем вызываю print(scope_list) или перебираю элементы списка. Сам запрос занимает всего несколько мс, но печать или итерация элементов снова занимает от 5 до 10 секунд, но набор имеет только две записи.

Серверная часть базы данных — Postgresql. Та же проблема возникает на локальном сервере разработки и apache.

Вот код модели:

class Scope(models.Model):
    title = models.CharField(primary_key=True, max_length=30)

    ## the semester the scope is linked with
    assoc_semester  =   models.ForeignKey(Semester, null=True) 

    ## the grade of the scope. can be Null if the scope is not a class
    assoc_grade     =   models.ForeignKey(Grade, null=True)

    ## the timetable of the scope. can be null if the scope is not direct associated with a class
    assoc_timetable =   models.ForeignKey(Timetable, null=True)

    ## the associated subject of the scope
    assoc_subject   =   models.ForeignKey(Subject)

    ## the calendar of the scope
    assoc_calendar  =   models.ForeignKey(Calendar)

    ## the usergroup of the scope
    assoc_usergroup =   models.ForeignKey(Group)

    members = models.ManyToManyField(User)

    unread_count = None

обновить

Вот вывод профилировщика python. Похоже, что query.py вызывался 1,6 миллиона раз — это слишком много. вывод профилировщика Python


person 7tupel    schedule 31.07.2013    source источник
comment
у этой модели есть метод __unicode__()? не могли бы вы опубликовать это?   -  person Hieu Nguyen    schedule 31.07.2013
comment
да, есть: def __unicode__(self): return self.title   -  person 7tupel    schedule 31.07.2013
comment
Я бы предложил установить панель инструментов отладки Django, чтобы вы могли видеть каждый запрос. Это даст вам гораздо лучшее представление о том, что замедляет вас.   -  person JcKelley    schedule 31.07.2013
comment
Вы тестируете это из оболочки django или из какой-то точки зрения? Является ли DEBUG верным или ложным в settings.py?   -  person Burhan Khalid    schedule 31.07.2013
comment
Обе упомянутые вами среды подключаются к одному и тому же серверу PostgreSQL, и если да, то используете ли вы имя хоста или IP-адрес в настройках базы данных?   -  person AndrewS    schedule 31.07.2013
comment
Вы можете установить geordi, чтобы полностью профилировать представление. Вы можете точно видеть, где все время тратится на каждую вызываемую функцию. Возможно, это все-таки не база данных.   -  person meshy    schedule 31.07.2013
comment
проблема возникает бут в представлениях и оболочке. стенды работают на разных машинах и используют свою собственную базу данных. я попробую панель инструментов отладки и георди   -  person 7tupel    schedule 31.07.2013
comment
@7tupel: у меня очень похожая проблема. Как вы решили это?   -  person caliph    schedule 04.12.2015


Ответы (2)


Вы должны попытаться сначала изолировать проблему. Запустите оболочку manage.py и выполните следующее:

scope = Scope.objects.get(pk='Esoterik I')
print scope

Теперь django-запросы не выполняются до тех пор, пока им очень не придется. То есть, если вы испытываете медлительность после первой строки, проблема кроется где-то в создании запроса, который предполагает проблемы с диспетчером объектов. Следующим шагом будет попытка выполнить необработанный SQL через django и убедиться, что проблема действительно связана с менеджером, а не с ошибкой в ​​​​django в целом.

Если вы испытываете медлительность со второй строкой, проблема либо с фактическим выполнением запроса, либо с отображением\печатью данных. Вы можете принудительно выполнить запрос, не распечатывая его (проверьте документацию), чтобы узнать, какой именно.

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

person yuvi    schedule 31.07.2013
comment
scope = Scope.objects.get(pk='Something') и Scope.objects.get(pk='something') занимают одинаковое время. если я использую filter() вместо get(), я сталкиваюсь с проблемами производительности при выполнении запроса (например, если я пытаюсь выполнить print() с содержимым набора запросов), поэтому кажется, что запрос построен правильно, но во время выполнения что-то идет не так - person 7tupel; 31.07.2013
comment
когда я пытаюсь выполнить необработанный запрос, выполнение занимает очень много времени. - person 7tupel; 31.07.2013

Чтобы быть уверенным во времени выполнения базы данных, лучше протестировать запросы, сгенерированные Django, поскольку запросы, сгенерированные Django, могут быть не простыми SELECT * from blah blah

Чтобы увидеть сгенерированный Django запрос:

_somedata = Scope.objects.filter(pk='Esoterik I') # you must use filter in here
print somedata.query.__format__('')

Это покажет вам полный запрос, сгенерированный Django. Затем скопируйте его, откройте консоль Postgresql и используйте инструменты анализа Postgresql:

EXPLAIN ANALYZE <your django query here>;

как:

EXPLAIN ANALYZE SELECT * FROMsomeapp_scope WHERE id = 'Esoterik I';

EXPLAIN покажет средние данные о выполнении, а ANAYLZE также покажет вам некоторые дополнительные данные о времени выполнения этого анализа.

Вы также можете увидеть, используется ли какой-либо индекс postgresql во время выполнения запроса в этих результатах анализа.

person FallenAngel    schedule 31.07.2013
comment
я пробовал это. необработанный запрос, сделанный django, занимает 26 мс, а простой SELECT * ... занимает 15 мс. так что кажется, что сгенерированный sql не проблема - person 7tupel; 31.07.2013