为什么在 BIGINT col 上的此查找具有额外的常量扫描、计算标量和嵌套循环运算符?

eck*_*kes 8 sql-server execution-plan cast sql-server-2014

当我查看一些查询的实际执行计划时,我注意到 WHERE 子句中使用的文字常量显示为计算标量常量 scan的嵌套链。

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)
Run Code Online (Sandbox Code Playgroud)

里面有一些数据:

INSERT INTO Table1(col1) VALUES (1),(2),(3),
                               (-9223372036854775808),
                               (9223372036854775807),
                               (2147483647),(-2147483648)
Run Code Online (Sandbox Code Playgroud)

当我运行以下(废话)查询时:

SELECT a.col1, a.col2
  FROM Table1 a, Table1 b
  WHERE b.col1 > 2147483648
Run Code Online (Sandbox Code Playgroud)

我看到它将在索引查找和标量计算(来自常量)的结果中执行嵌套循环绘图。

请注意,文字大于 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 64bit 中看到了这一点,但我想这是一种一般行为。

Mar*_*ith 9

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)
Run Code Online (Sandbox Code Playgroud)

向您展示文字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])
Run Code Online (Sandbox Code Playgroud)

您可以使用扩展事件会话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>
Run Code Online (Sandbox Code Playgroud)

这并不意味着它实际上是在进行比较,< null而不是

范围边界表达式使用 NULL 来表示两端的“无界”。来源

所以最终效果是您的查询谓词b.col1 > CAST(2147483648 AS NUMERIC(10, 0))仍然以针对b.col1 > CAST(2147483648 AS BIGINT)

它是否也会影响到准备好的语句(来自 jtds JDBC)的绑定参数?

我没有使用过 jtds JDBC,但我认为它允许您定义参数数据类型?如果是这样,只需确保参数是与列 ( bigint)匹配的正确数据类型,这样 SQL Server 就无需处理不匹配的数据类型。