Sql-Server

為什麼在 BIGINT col 上的這種搜尋具有額外的常量掃描、計算標量和嵌套循環運算符?

  • November 15, 2019

當我查看一些查詢的實際執行計劃時,我注意到 WHERE 子句中使用的文字常量顯示為計算標量常量掃描的嵌套鍊。

sql工作室截圖

為了重現這一點,我使用下表

CREATE TABLE Table1 (
   [col1] [bigint] NOT NULL,
   [col2] [varchar](50) NULL,
   [col3] [char](200) NULL
)
CREATE NONCLUSTERED INDEX IX_Table1 ON Table1 (col1 ASC)

裡面有一些數據:

INSERT INTO Table1(col1) VALUES (1),(2),(3),
                              (-9223372036854775808),
                              (9223372036854775807),
                              (2147483647),(-2147483648)

當我執行以下(廢話)查詢時:

SELECT a.col1, a.col2
 FROM Table1 a, Table1 b
 WHERE b.col1 > 2147483648

我看到它將在 Index Seek 的結果中進行嵌套循環繪圖和標量計算(來自常數)。

請注意,字面量大於 maxint。它確實有助於寫作CAST(2147483648 as BIGINT)。知道為什麼 MSSQL 將其推遲到執行計劃並且有比使用強制轉換更短的方法來避免它嗎?它是否也會影響到準備好的語句(來自 jtds JDBC)的綁定參數?

標量計算並不總是完成(似乎是特定於索引搜尋的)。有時查詢分析器不會以圖形方式顯示它,而是col1 < scalar(expr1000)在謂詞屬性中顯示。

我在 Windows 7 上使用 MS SSMS 2016 (13.0.16100.1) 和 SQL Server 2014 Express Edition 64bit 看到了這一點,但我想這是一種普遍的行為。

SELECT thing, 
      sql_variant_property(thing,'basetype') AS basetype,
      sql_variant_property(thing,'precision') AS precision, 
      sql_variant_property(thing,'scale') AS scale
FROM (VALUES (2147483648)) V(thing)

顯示文字2147483648被解釋為numeric(10,0). 此行為早bigint於 SQL Server (2000) 中的引入。

沒有語法表明應該將文字視為bigint- 添加顯式CAST是最好的解決方案。動態搜尋和隱藏的隱式轉換一文討論了計劃中的其餘設備。

該計劃本身表明嵌套循環有一個搜尋謂詞

Seek Keys[1]: Start: [tempdb].[dbo].[Table1].col1 > Scalar Operator([Expr1005]), 
               End: [tempdb].[dbo].[Table1].col1 < Scalar Operator([Expr1006])

您可以使用擴展事件會話query_trace_column_values來查看這些內容如下。

在此處輸入圖像描述

計劃中的 XML 也顯示了這一點

 <DefinedValue>
   <ValueVector>
     <ColumnReference Column="Expr1005" />
     <ColumnReference Column="Expr1006" />
     <ColumnReference Column="Expr1004" />
   </ValueVector>
   <ScalarOperator ScalarString="GetRangeWithMismatchedTypes((2147483648.),NULL,(6))">
     <Intrinsic FunctionName="GetRangeWithMismatchedTypes">
       <ScalarOperator>
         <Const ConstValue="(2147483648.)" />
       </ScalarOperator>
       <ScalarOperator>
         <Const ConstValue="NULL" />
       </ScalarOperator>
       <ScalarOperator>
         <Const ConstValue="(6)" />
       </ScalarOperator>
     </Intrinsic>
   </ScalarOperator>
 </DefinedValue>

這並不意味著它實際上是在進行比較< null,而是

範圍邊界表達式使用 NULL 來表示兩端的“無界”。(來源

所以最終結果是您的查詢謂詞b.col1 > CAST(2147483648 AS NUMERIC(10, 0))仍然以尋求反對而告終b.col1 > CAST(2147483648 AS BIGINT)

它是否也會影響到準備好的語句(來自 jtds JDBC)的綁定參數?

我沒有使用過 jtds JDBC,但我認為它允許您定義參數數據類型?如果是這樣,只需確保參數是與列 ( bigint) 匹配的正確數據類型,這樣 SQL Server 就無需處理不匹配的數據類型。

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