為什麼在 BIGINT col 上的這種搜尋具有額外的常量掃描、計算標量和嵌套循環運算符?
當我查看一些查詢的實際執行計劃時,我注意到 WHERE 子句中使用的文字常量顯示為計算標量和常量掃描的嵌套鍊。
為了重現這一點,我使用下表
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 就無需處理不匹配的數據類型。