簡體   English   中英

在 PostgreSQL 中使用 LEFT JOIN 而不是 NOT IN

[英]Using LEFT JOIN instead of NOT IN in PostgreSQL

我正在調試 django-reversion(django 庫)中可能存在的性能錯誤。 我遇到的問題是,每次運行 django-reversion 的createinitialrevisions ,我的數據庫都會花費大量時間來處理正在發生的事情。

我在 RDS 中啟用了 Performance Insights,我看到正在殺死我的數據庫的查詢如下所示:

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 是不能以與LEFT JOIN相同的方式優化NOT IN 這就是為什么我決定重寫這個查詢並查看它是否需要相同的時間來運行。

這是重寫后的結果:

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'

我一定是做錯了什么,因為我得到了不同的結果。 我的查詢(重寫的查詢)根本沒有返回任何內容。

我錯過了什么?

正確重寫的查詢需要前一個子查詢的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的連接子句。 細微但根本的區別。

看:

關於性能可能還有更多要說的,但並非沒有設置的必要細節......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM