发现某一条语句消耗较高,执行比较频繁
隐式转换
数据库版本如下
隐式转换
将TextData语句拷贝到查询窗口执行
隐式转换
隐式转换
将sp_executesql中的主体语句拷贝到查询窗口执行
隐式转换
隐式转换
执行计划的总体流向是一致的,根据token得到LKLoginTokenRecord,然后嵌套循环AccountsInfoSimple。但是sp_executesql语句的执行计划有常量扫描和计算标量的操作,并且在索引查找中有谓词CONVERT_IMPLICIT(nvarchar(32),[DBname].[dbo].[LKLoginTokenRecord].[Token] as [a].[Token],0)=[@0]
常量扫描和计算标量操作的文本计划如下
隐式转换

|--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1008], [Expr1009], [Expr1007]))
|    |--Compute Scalar(DEFINE:(([Expr1008],[Expr1009],[Expr1007])=GetRangeThroughConvert([@0],[@0],(62))))
|    |    |--Constant Scan
|    |--Index Seek(OBJECT:([DBname].[dbo].[LKLoginTokenRecord].[IX_Token] AS [a]), SEEK:([a].[Token] > [Expr1008] AND [a].[Token] < [Expr1009]),  WHERE:(CONVERT_IMPLICIT(nvarchar(32),[LK78DB].[dbo].[LKLoginTokenRecord].[Token] as [a].[Token],0)=[@0]) ORDERED FORWARD)

最开始一直不明白为什么会多出两个操作,明明很简单的语句,并且LKLoginTokenRecord在Token上有索引。sp_executesql的执行计划怎么就变得那么复杂?
以下段落来自微软亚太区数据库技术支持组 官方博客

我们注意到,这里出现了一个操作叫做GetRangeThroughConvert().在这里,SQL Server由于不能直接对varchar(32)的列用nvarchar(4000)的值进行seek,因此,SQL Server必须将nvarchar转换成varchar。但是由于这个转换可能导致数据丢失,SQL Server采用了另一种做法,首先扩展了一个varchar类型的范围,确保可以转换成我们目标的nvarchar值的varchar数据落在这个范围之内,然后使用这个范围去对index直接做seek。得到了返回的满足范围的少量数据以后,对这个范围内的少量数据进行数据类型转换,然后用来和nvarchar的值比较,最终准确的返回结果集。在这样一个过程中,SQL Server采用了一种迂回的方式使用了index seek而避免了表扫描。

就是说通过常量扫描和计算标量,SQL Server得到一个"缩小"范围的集合,然后针对集合内的数据进行转换并比较。实际就是减少需要隐式转换的数量。
因此问题语句出在隐式转换CONVERT_IMPLICIT,检查LKLoginTokenRecord表,Token字段类型为varchar(32)。sp_executesql语句的参数定义列表将@0定义为nvarchar(4000),它传递到主体语句时,等效语句

SELECT a.userID,b.accounts AS Account,b.nickName,a.ExpireDate as TokenExpireDate
FROM LKLoginTokenRecord a WITH(NOLOCK)
INNER JOIN AccountsInfoSimple b WITH(NOLOCK)
ON a.UserID=b.userID
WHERE convert(nvarchar(32),token)=convert(nvarchar(4000),'65F2032A36C0477CBA602E7232BD6B49')
ORDER BY a.ExpireDate desc
View Code

相关文章:

  • 2021-05-11
  • 2021-08-20
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-10-21
  • 2022-12-23
  • 2021-11-16
  • 2021-09-08
  • 2021-12-12
相关资源
相似解决方案