Использование LEFT JOIN вместо NOT IN в PostgreSQL - PullRequest
2 голосов
/ 16 марта 2019

Я отлаживаю возможную ошибку производительности в django-reversion (библиотека django).Проблема, с которой я сталкиваюсь, заключается в том, что каждый раз, когда я запускаю django-reversion createinitialrevisions, моей БД будет требоваться огромное количество времени для обработки того, что происходит.

Я включил Performance Insights в RDS иЯ вижу, что запрос, который убивает мою БД, выглядит следующим образом:

SELECT "table_a"."id"
FROM "table_a"
WHERE NOT (CAST("table_a"."id" as text) IN (
        SELECT U0."object_id"
        FROM "reversion_version" U0
        WHERE (U0."content_type_id" = 49 AND U0."db" = 'default')
))

Если я правильно понимаю, что я читаю здесь https://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/, оказывается, что PostgreSQL не может оптимизировать то же самоеспособ NOT IN, чем LEFT JOIN.Вот почему я решил переписать этот запрос и посмотреть, будет ли выполняться столько же времени.

Вот результат после его переписывания:

SELECT "table_a"."id"
FROM "table_a"
LEFT JOIN 
        "reversion_version" U0
ON U0."object_id" = "table_a"."id"::text
WHERE U0."object_id" IS NULL AND U0."content_type_id" = 49 AND U0."db" = 'default'

Я должен был что-то сделатьнеправильно, потому что я получаю разные результаты.Мой запрос (переписанный) вообще ничего не возвращает.

Что я пропустил?

1 Ответ

2 голосов
/ 16 марта 2019

Правильно переписанному запросу нужны условия WHERE предыдущего подзапроса в качестве условий соединения с LEFT JOIN, например:

SELECT table_a.id
FROM   table_a
LEFT   JOIN  reversion_version U0 ON U0.object_id = table_a.id::text
                                 AND U0.content_type_id = 49
                                 AND U0.db = 'default'
WHERE  U0.object_id IS NULL;

То, как вы пытались, было логическим противоречием: он запрашивал строкив table_a без соответствующей строки в reversion_version и тогда налагает дополнительные условия на несуществующие строки.Это никогда не может вернуть никаких строк.

Должно быть наоборот: найти строки в table_a без соответствующей строки в reversion_version, которая бы удовлетворяла указанным условиям.Следовательно, переместите эти условия из предложения WHERE в предложение объединения LEFT JOIN.Тонкое, но принципиальное отличие.

См .:

Можно сказать больше о производительности, но не без необходимых деталей вашей настройки ...

...