Sql server SQL Server索引使用和隐式转换

Sql server SQL Server索引使用和隐式转换,sql-server,Sql Server,请有人向我解释以下行为,让我知道表定义等是否有帮助 我在SQL Server 2016 SP2上执行了一个查询,所有表的主键列上都有默认的聚集索引,这是一个IDENTITY列: SELECT a.smallint_col FROM TableA a INNER JOIN TableB b ON b.int_col = a.int_col WHERE a.int_col = 123 AND b.varchar_col = 12345; 此查询返回一个错误: 将varchar值“ABC123”转换

请有人向我解释以下行为,让我知道表定义等是否有帮助

我在SQL Server 2016 SP2上执行了一个查询,所有表的主键列上都有默认的聚集索引,这是一个
IDENTITY
列:

SELECT a.smallint_col
FROM TableA a
INNER JOIN TableB b ON b.int_col = a.int_col
WHERE a.int_col = 123 AND b.varchar_col = 12345;
此查询返回一个错误:

将varchar值“ABC123”转换为数据类型int时,转换失败

'ABC123'
表b.varchar\u col
中一行的值

我理解此查询强制SQL Server在
TableB.varchar\u col
上执行隐式转换,因为它在传递时没有单引号

我可以从Include Live Query Statistics中看出,此查询试图对表B上定义的索引使用非聚集索引扫描,如下所示:

CREATE NONCLUSTERED INDEX [varchar_col] 
ON [TableB] ([varchar_col])
以及表A中定义的索引上的索引搜索:

CREATE NONCLUSTERED INDEX [int_col] 
ON [TableA] ([int_col])
如果通过使用
WITH(INDEX(1))
强制查询在每个表上使用聚集索引,则查询将成功返回。我知道,如果我正确地引用了值
'12345'
,查询也会成功返回(出于某种未知原因,我们的代码在没有引号的情况下通过了它),我认为这才是真正的解决方案


但是,我想在这里了解SQL Server的行为。为什么聚集索引扫描能够在不抛出错误的情况下执行隐式转换,而非聚集索引扫描却不能?

这里发生的可能是SQL Server应用子句的顺序

当出现故障时,数据引擎可能首先应用子句
b.varchar\u col=12345
。因此,当比较无法(隐式)转换为
int
的值时,查询将失败

在它工作的时候,很可能首先对子句
a.int\u col=123
进行评估。应用此选项时,保留的任何行都包含可以隐式转换的
b.varchar\u col
中的值,因此不会出现故障

但是,正如您所说,这里真正的解决方案是纠正您的应用程序层。您可能应该使用参数化查询,而不是(注入?)原始值。然后控制数据类型:

SELECT a.smallint_col
FROM TableA a
INNER JOIN TableB b ON b.int_col = a.int_col
WHERE a.int_col = @IntParam and b.varchar_col = @VarcharParam;
然后,在应用程序代码中,可以将
@IntParam
定义为
int
,将
@VarcharParam
定义为
varchar
,这意味着除非应用程序将
12345
传递给参数
@VarcharParam
,否则不会发生隐式转换


但是,如何参数化应用程序是一个不同的问题(因为我们甚至不知道应用程序使用什么语言,恐怕我们甚至无法提供示例)。

要理解计划,必须查看计划、所涉及对象的DDL和实际查询。不要发布图片-用于发布您的计划并将其链接到您的问题中。请尝试使用
。。。。b.varchar_col='12345'。如果此值周围没有单引号,SQL Server将尝试将等号的两侧转换为具有更高优先级的数据类型-即
int
-SQL Server尝试(但失败)将
b.varchar\u col
转换为
int
-因此出现错误消息Thank@Larnu。该应用程序是使用VBScript的经典ASP,大多数查询都作为原始T-SQL传递。我正在与我们的开发人员合作,希望正确地参数化并解决大量导致大量隐式转换的数据类型不匹配问题。