оптимизация запросов к базе данных django - PullRequest
1 голос
/ 30 ноября 2011

вопрос новичка по оптимизации запросов django db:

У меня есть пользовательская форма модели для редактирования объекта Destination, и я в конструкторе получаю набор запросов из связанной модели Visitor, которая имеет поле ManyToMany в Destination (см. РЕДАКТИРОВКУ о том, как использовать пользовательскую форму модели). )

    print "loading initial choices"
    visitor_choices, visitor_initial = [], []
    visitor_set = self.instance.visitor_set.all()
    print visitor_set
    for obj in Visitor.objects.all():
        visitor_choices.append((obj.pk, obj.name))
        #if visitor_set.filter(pk=obj.pk # this hits the db every time!
        if obj in visitor_set:
            visitor_initial.append(obj.pk)

    self.fields['visitors'].choices = visitor_choices
    self.fields['visitors'].initial = visitor_initial

    print "finished loading initial choices"

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

Кроме того, если я включаю ведение журнала базы данных (как объяснено в этом вопросе , второй ответ), я вижу повторяющийся запрос (3-й оператор SELECT), чтобы выбрать всех посетителей для идентификатора назначения 1, но это нигде в коде, который я написал, откуда он взялся?

loading initial choices
(0.000) SELECT "testapp_visitor"."id", "testapp_visitor"."name" FROM "testapp_visitor" INNER JOIN "testapp_visitor_destinations" ON ("testapp_visitor"."id" = "testapp_visitor_destinations"."visitor_id") WHERE "testapp_visitor_destinations"."destination_id" = 1  LIMIT 21; args=(1,
)
[<Visitor: MIMA>, <Visitor: MIMO>, <Visitor: MIMU>]
(0.000) SELECT "testapp_visitor"."id", "testapp_visitor"."name" FROM "testapp_visitor"; args=()
(0.000) SELECT "testapp_visitor"."id", "testapp_visitor"."name" FROM "testapp_visitor" INNER JOIN "testapp_visitor_destinations" ON ("testapp_visitor"."id" = "testapp_visitor_destinations"."visitor_id") WHERE "testapp_visitor_destinations"."destination_id" = 1 ; args=(1,)
finished loading initial choices

EDIT

Объект Destination, на который я ссылаюсь, является связанной стороной поля ManyToMany объекта Visitor. Если бы моя форма редактировала сам объект Visitor, тогда Django автоматически обработал бы поле ManyToMany. Но чтобы сделать это в форме модели для Destination, мне нужно добавить поле множественного выбора для Visitor и настроить метод __init__ для загрузки вариантов и начальных вариантов выбора для него.

Однако вопрос заключается в том, как обрабатывать набор запросов, и о таинственном втором sql для загрузки многих значений, которые я также вижу из оболочки:

>>> from testapp.forms import DestinationForm
>>> from testapp.models import Destination, Visitor
>>> dest = Destination.objects.get(pk=1)
(0.001) SELECT "testapp_destination"."id", "testapp_destination"."destination" FROM "testapp_destination" WHERE "testapp_destination"."id" =
 1 ; args=(1,)
>>> destinationForm = DestinationForm(instance=dest)
loading initial choices
(0.000) SELECT "testapp_visitor"."id", "testapp_visitor"."name" FROM "testapp_visitor" INNER JOIN "testapp_visitor_destinations" ON ("testap
p_visitor"."id" = "testapp_visitor_destinations"."visitor_id") WHERE "testapp_visitor_destinations"."destination_id" = 1  LIMIT 21; args=(1,
)
[<Visitor: MIMA>, <Visitor: MIMO>, <Visitor: MIMU>]
(0.000) SELECT "testapp_visitor"."id", "testapp_visitor"."name" FROM "testapp_visitor"; args=()
(0.000) SELECT "testapp_visitor"."id", "testapp_visitor"."name" FROM "testapp_visitor" INNER JOIN "testapp_visitor_destinations" ON ("testap
p_visitor"."id" = "testapp_visitor_destinations"."visitor_id") WHERE "testapp_visitor_destinations"."destination_id" = 1 ; args=(1,)
finished loading initial choices
>>>

Спасибо

1 Ответ

1 голос
/ 14 декабря 2011

Чтобы ответить на то, что вы говорите, ваш вопрос: я думаю, что запрос

SELECT "testapp_visitor"."id", "testapp_visitor"."name" FROM "testapp_visitor" INNER JOIN "testapp_visitor_destinations" ON ("testapp_visitor"."id" = "testapp_visitor_destinations"."visitor_id") WHERE "testapp_visitor_destinations"."destination_id" = 1 ; args=(1,)

происходит от линии

if obj in visitor_set:

, где Django повторно выполняет запрос visitor_set (см. Когда QuerySets оценивается в документации Django). Вы можете избежать этого, преобразовав visitor_set в set сразу (таким образом, Django вынужден немедленно выполнить запрос), как в:

visitor_set = set(self.instance.visitor_set.all())

Это также улучшит производительность тестирования, находится ли объект в этом наборе (по сравнению с list или аналогичным повторяемым).

...