SQL SERVER中隐式转换的一些细节浅析

原文: SQL SERVER中隐式转换的一些细节浅析

其实这是一篇没有技术含量的文章,精通SQL优化的请绕道。这个缘起于在优化一个SQL过程当中,同事问了我一个问题,为何SQL中存在隐式转换,可是执行计划没有变? 我思索了一下,以为这个问题也有点意思,说不定有些对隐式转换了解得不深刻的同窗都有此疑问,那么下面结合上下文场景作一个细节方面的解答。 html

咱们一个系统中使用了ORMLite框架,粗心的开发人员弄出了很多下面这样的SQL语句,都存在隐式转换问题,以下所示,表machine_stop_alarm_msg 的结构以下,字段machine_no、status都为VARCHAR(10),可是下面SQL,传入的变量@P0,@P1都是NVARCHAR(4000)类型。 框架

 

clipboard

DECLARE  @P0 nvarchar(4000),@P1 nvarchar(4000);
 
SET @P0='1';
SET @P1='K172';
 
SELECT [recid],[machine_no]
   ,[stop_stime]
   ,[stop_etime]
   ,[status]
   ,[memo]
   ,[createddate] 
FROM machine_stop_alarm_msg t 
WHERE 1=1 
AND t.status=@P0 
AND t.machine_no in(@P1 ) 
ORDER BY machine_no,
   stop_stime ; 

 

 

machine_stop_alarm_msg 表只有一个汇集索引PK_machine_stop_alarm_msg,字段为recid。 oop

clipboard

 

当时我优化的时候,就以为这个SQL语句存在两个问题:1 缺乏索引; 2 存在隐式转换问题。当时建立了下面索引,并要求开发人员修改SQL,避免隐式转换。测试

CREATE NONCLUSTERED INDEX ix_machine_stop_alarm_msg_n1
ON [dbo].[machine_stop_alarm_msg] ([machine_no],[status])
INCLUDE ([recid],[stop_stime],[stop_etime],[memo],[createddate])
GO

 

 

在测试环境测试时,咱们先不增长这个索引,就出现了下面一个场景,二者都是走汇集索引扫描: 优化

 

1: 执行计划走汇集索引扫描(Cluster Index Scan)spa

SET STATISTICS IO ON;
SET STATISTICS TIME ON;
DECLARE  @P0 nvarchar(4000),@P1 nvarchar(4000);
 
SET @P0='1';
SET @P1='K172';
SELECT [recid],[machine_no]
   ,[stop_stime]
   ,[stop_etime]
   ,[status]
   ,[memo]
   ,[createddate] 
FROM machine_stop_alarm_msg t 
WHERE 1=1 
AND t.status=@P0 
AND t.machine_no in(@P1 ) 
ORDER BY machine_no,
   stop_stime ; 
 
SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;

clipboard

clipboard

 

2: 执行计划走汇集索引扫描(Cluster Index Scan) 3d

 

SET STATISTICS IO ON;
SET STATISTICS TIME ON;
DECLARE  @P0 VARCHAR(10),@P1 VARCHAR(10);
 
SET @P0='1';
SET @P1='K172';
SELECT [recid],[machine_no]
   ,[stop_stime]
   ,[stop_etime]
   ,[status]
   ,[memo]
   ,[createddate] 
FROM machine_stop_alarm_msg t 
WHERE 1=1 
AND t.status=@P0 
AND t.machine_no in(@P1 ) 
ORDER BY machine_no,
   stop_stime ; 
 
SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;

clipboard

 

这里二者的执行计划同样,这个应该很好理解,缺乏相关索引,并且发生隐式转换的不是索引所在的字段,那么即便存在隐式转换,它的执行计划是同样的。 这里没有太多要解释的。 code

那么咱们接下来看看看增长了索引后,二者的实际执行计划。 htm

 

clipboard

clipboard

 

如今同事纠结的就是即便发生了隐式转换,为何执行计划仍是走索引查找(Index Seek)呢? 其实不少人有一个误区,SQL Server当中并非全部的隐式转换都会致使索引扫描(Index Scan),关于这个请见我这篇博客SQL SERVER中什么状况会致使索引查找变成索引扫描 。也就是说隐式转致使索引扫描也是有条件的。这里再也不作展开讲,没有太多意思。另外,咱们再来对比一下二者的执行计划。 blog

 

上面发生隐式转换的SQL的执行计划,多了一个常量扫描(Constant Scan),常量扫描作的工做是根据用户输入的SQL中的常量生成一个行 ,MSDN的介绍以下:

"The Constant Scan operator introduces one or more constant rows into a query. A Compute Scalar operator is often used after a Constant

Scan to add columns to a row produced by the Constant Scan operator"

 

常量扫描会引入一个或者多个常量行到一个查询中;一般状况下紧跟常量扫描的是计算标量运算符,计算标量运算符会为常量扫描运算符产生的行添加列。

clipboard

若是你想知道执行计划里面的Expr100四、 Expr100五、Expr1003对应啥,看看执行计划就知道了(其中Expr1003为(62),一开始不明其什么意义,后面咨询了宋大神,才知道62是个flag,意思是等于号)

clipboard

 

发生隐式转换的SQL还多了一个Nested Loop(Inner Join)操做。另外,即便这两个SQL依然都是索引查找(Index Seek),可是两种的IO开销仍是有所区别的。

clipboard

 

image

 

 

clipboard

 

image

相关文章
相关标签/搜索