当我查看一些查询的实际执行计划时,我注意到 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
我看到它将在索引查找和标量计算(来自常量)的结果中进行嵌套循环绘图。
请注意,文字大于 maxint。它确实有助于写作CAST(2147483648 as BIGINT)
。知道为什么 MSSQL 将其推迟到执行计划并且有没有比使用强制转换更短的方法来避免它?它是否也会影响到准备好的语句(来自 jtds JDBC)的绑定参数?
标量计算并不总是完成(似乎是特定于索引查找的)。有时查询分析器不会以图形方式显示它,而是col1 < scalar(expr1000)
在谓词属性中显示。
我已经在 Windows 7 上使用 MS SSMS 2016 (13.0.16100.1) 和 SQL Server 2014 Expres Edition 64 位看到过这种情况,但我想这是一种普遍行为。
向您展示文字
2147483648
被解释为numeric(10,0)
. 此行为早bigint
于 SQL Server (2000) 中的引入。没有语法表明应将文字视为
bigint
- 添加显式CAST
是最佳解决方案。文章Dynamic Seeks and Hidden Implicit Conversions讨论了计划中的其他工具。该计划本身表明嵌套循环有一个搜索谓词
您可以使用扩展事件会话
query_trace_column_values
来查看这些内容,如下所示。计划中的 XML 也显示了这一点
这并不意味着它实际上是在进行比较
< null
,而是所以最终的结果是你的查询谓词
b.col1 > CAST(2147483648 AS NUMERIC(10, 0))
仍然以查找结束b.col1 > CAST(2147483648 AS BIGINT)
我没有使用过 jtds JDBC,但我认为它允许您定义参数数据类型?如果是这样,只需确保参数是与列 (
bigint
) 匹配的正确数据类型,这样 SQL Server 就不需要处理不匹配的数据类型。关于我关于 JDBC 准备语句的问题。jTDS使用
sp_prepare
/sp_execute
(在默认prepareSQL=3
模式下)。使用以下查询(来源):
我可以看到 JTDS 发出的准备好的语句,它确实
(@P0 bigint)...
按预期声明了变量。所以这一切都很好,我需要记住,在尝试执行计划时,最好实际定义本地类型变量而不是用文字替换它们(和/或使用
sp_execute
缓存的执行计划)。