邏輯運算符使用不當導致查詢性能不佳
我有一張包含大量數據(近 1500 萬)及以下結構的表格。
create table test (a int,--> /* There is a normal index on this column */ b int, <other columns>)
有一個從此表中選擇的查詢,where 子句中的條件之一是:
where a!=1 or (a=1 and b!=0) /* The original condition */
查詢非常慢,我認為這種糟糕的性能大部分可能是因為邏輯運算符使用不當。我已經改變了條件,如下所示:
where not (a=1 and b=0) /* The edited version*/
並且性能發生了巨大變化!我需要確定的是這兩個條件完全相同,所以我不會錯過任何數據。我想知道您是否可以幫助我,並告訴我您是否有更好的替代方案。
如果您知道任何關於正確使用邏輯操作以及方式/順序優化器處理它們的文章,請分享連結。
提前致謝
為了確定兩個條件是否真的等價,您可以嘗試為每個條件建構真值表,看看這兩個表是否相同。
以下是建構真值表的方法。您有兩個變數,
a
,可能等於或不等於 1,和b
,可能等於或不等於 0。編寫並執行如下查詢:SELECT a , b , [a!=1 or (a=1 and b!=0)] = CASE WHEN a!=1 or (a=1 and b!=0) THEN 'True' ELSE 'False' END , [not (a=1 and b=0)] = CASE WHEN not (a=1 and b=0) THEN 'True' ELSE 'False' END FROM ( VALUES ( 1, 0) , ( 1, 9999) , (9999, 0) , (9999, 9999) ) AS v (a, b) ;
對於每個變數,指定與變數進行比較的值,以便進行相應的比較或真或假(取決於它是
=
還是!=
),以及產生相反結果的另一個值。上面的值 9999 只是一個任意值,在與 的比較時代表“非 1”,在與 的比較時代表a
“非 0”b
。(我選擇了與 1 或 0 完全不同的東西,以免結果表過於混亂。)上述查詢將返回以下輸出:
如您所見,對於相同的輸入值,兩個表達式給出相同的結果。
但是請注意,上表僅包含使比較評估為True或False的值。這就是布爾代數中通常的情況。但是,在 SQL 世界中,布爾表達式可以評估為第三種狀態,即Unknown aka Null。如果
a
可以為空並且確實為空,那麼a=1
(或a!=1
就此而言)將評估為Unknown / Null。如果需要考慮可空性,那麼我們的真值表應該包含空值作為輸入值。這是上述腳本的修改版本,其中包含兩個變數的空值:
SELECT a , b , [a!=1 or (a=1 and b!=0)] = CASE WHEN a!=1 or (a=1 and b!=0) THEN 'True' WHEN NOT (a!=1 or (a=1 and b!=0)) THEN 'False' ELSE 'Unknown' END , [not (a=1 and b=0)] = CASE WHEN not (a=1 and b=0) THEN 'True' WHEN NOT (not (a=1 and b=0) ) THEN 'False' ELSE 'Unknown' END FROM ( VALUES ( 1, 0) , ( 1, 9999) , ( 1, NULL) , (9999, 0) , (9999, 9999) , (9999, NULL) , (NULL, 0) , (NULL, 9999) , (NULL, NULL) ) AS v (a, b) ;
它給出了以下輸出:
上面突出顯示的是兩個條件不產生相同結果的一種情況,即當
a
為空並且b
是非 0 的非空值時。在這種情況下,第一個條件的結果是未知的,而另一個條件的結果為真。同樣,這是假設
a
可以為空,並且在該假設下,您的兩個邏輯表達式不等價。但是,例如,只能b
為空,不能為空a
,那麼您可以從上面的輸出中看到對應行中的結果是相同的。因此,您將根據所涉及變數的可空性找到答案。
更多閱讀的幾個連結: