SQL Server 如何知道何时隐式转换值

3 sql-server type-conversion sql-server-2014

按照我之前的问题:隐式转换不会影响性能

我使用了下面的简单查询

select count(*)
from fpc
where SKey in ('201701', '201702A')
Run Code Online (Sandbox Code Playgroud)

SKey 是 int 类型,我在它上面有非聚集列存储索引。

显然我无法运行它,因为第二个值不是数字。所以我按 Ctrl+L 来查看估计的执行计划,我在Predicate属性中看到了一个有趣的事情:

[mydb].[dbo].[fpc].[SKey]=CONVERT_IMPLICIT(int,'201702A',0) OR
[mydb].[dbo].[fpc].[SKey]=(201701)
Run Code Online (Sandbox Code Playgroud)

我的问题是为什么 SQL 使用“201701”作为数字,但对第二个值使用隐式转换:“201702A”

我感兴趣的是 SQL 服务器如何查看这两个值的内部机制。它知道第一个是数字而第二个不是吗?

Pau*_*ite 10

我的问题是为什么 SQL 使用“201701”作为数字,但对第二个值使用隐式转换:“201702A”

我感兴趣的是 SQL 服务器如何查看这两个值的内部机制。它知道第一个是数字而第二个不是吗?

SQL Server 尝试将两个字符串转换为正确的类型(根据数据类型优先规则),以便Skey在查询编译的常量折叠阶段与整数列进行比较。此活动发生在流程的早期,甚​​至在考虑最简单的查询计划之前就发生了。

当常量折叠成功时,输入树包含派生的文字值(作为正确的类型)并继续优化,就像查询编写者使用了常量而不是表达式一样。

当常量折叠不成功时(例如因为转换会抛出错误),树包含一个转换函数。在编译时抛出错误是不正确的;只有在执行查询时才会发生错误,并且实际评估有问题的表达式(如果有的话)。

因此,在您的情况下,'201701' 被常量折叠为整数 201701,但 '201702A' 变为CONVERT_IMPLICIT(int,'201702A',0).

常量折叠比上面的简单示例所暗示的更强大和更完整。例如:

LastName LIKE SUBSTRING(LEFT(NCHAR(UNICODE(NCHAR(68))), 1) + N'%', 1, 2)
Run Code Online (Sandbox Code Playgroud)

被常数折叠为:

LastName LIKE N'D%'
Run Code Online (Sandbox Code Playgroud)

在 SQL Server 2012 及更高版本中,即使是确定性 SQLCLR 标量函数也可以进行常量折叠。