Sql-Server

邏輯運算符使用不當導致查詢性能不佳

  • October 24, 2021

我有一張包含大量數據(近 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 完全不同的東西,以免結果表過於混亂。)

上述查詢將返回以下輸出:

如您所見,對於相同的輸入值,兩個表達式給出相同的結果。

但是請注意,上表僅包含使比較評估為TrueFalse的值。這就是布爾代數中通常的情況。但是,在 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,那麼您可以從上面的輸出中看到對應行中的結果是相同的。

因此,您將根據所涉及變數的可空性找到答案。

更多閱讀的幾個連結:

引用自:https://dba.stackexchange.com/questions/301557