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

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

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

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。

当时我优化的时候,就觉得这个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)

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;

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

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;

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

那么我们接下来看看看增加了索引后,两者的实际执行计划。

现在同事纠结的就是即使发生了隐式转换,为什么执行计划还是走索引查找(Index Seek)呢? 其实很多人有一个误区,SQL Server当中并不是所有的隐式转换都会导致索引扫描(Index Scan),关于这个请见我这篇博客SQL SERVER中什么情况会导致索引查找变成索引扫描 。也就是说隐式转导致索引扫描也是有条件的。这里不再做展开讲,没有太多意思。另外,我们再来对比一下两者的执行计划。

上面发生隐式转换的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"

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

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

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

SQL SERVER中隐式转换的一些细节浅析相关推荐

  1. SQL Server中行列转换 Pivot UnPivot (转载)

    SQL Server中行列转换 Pivot UnPivot PIVOT用于将列值旋转为列名(即行转列),在SQL Server 2000可以用聚合函数配合CASE语句实现PIVOT的一般语法是:PIV ...

  2. html中隐式转换成数字,详解JS中的隐式类型转换

    JS中隐式类型转换 JS中的数据类型 JS中的数据类型分为两大类: 1.基本数据类型: 1.String 字符串 表示一段文本,例如:人的姓名.地址等 2.Number 数值 3.Boolean 布尔 ...

  3. SQL Server全时区转换

    SQL Server全时区转换 假如你的应用程序是跨国(例如跨国银行交易)使用的话,那么数据库的一些国际化特性支持可以说是非常重要 其中最常见的就是各国时区上的差异,由于SQL Server getd ...

  4. SQL Server 数据库之转换函数

    转换函数 1. 概述 2. Cast 函数 3. Convert 函数 1. 概述 SQL Server 数据库中,不同类型的数据进行运算时:游优先级低的类型会自动转换为优先级搞得数据类型,即隐式转换 ...

  5. sqlserver2000换成mysql_将Microsoft SQL Server 2000数据库转换成MySQL数据库

    1. 下载并安装MyODBC.(如果是XP请下载5.3的旧版本,8.x的新版本运行有问题) 2. 创建一个空的MySQL数据库. 3. 在Windows >> 控制面板 >> ...

  6. 也议MySQL中隐式转换

    1. 环境说明 blog地址:http://blog.csdn.NET/hw_libo/article/details/39252427 RHEL 6.4 x86_64 + MySQL 5.6.19 ...

  7. SQL server日期格式转换

    日期格式转换 字符串转日期时间: convert(datetime,'2017-12-12 00:00:01', 20) 日期时间转字符串: Select CONVERT(varchar(100), ...

  8. Sql Server 日期格式转换

    轉自:http://www.cnblogs.com/JoeDZ/archive/2008/08/19/1270917.html SQL Server中文版的默认的日期字段datetime格式是yyyy ...

  9. 【转】SQL Server中行列转换 Pivot UnPivot

    PIVOT用于将列值旋转为列名(即行转列),在SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT的一般语法是:PIVOT(聚合函数(列) FOR 列 in (-) )AS P ...

  10. SQL Server日期格式转换大全

    Sql Server 中一个非常强大的日期格式化函数 Select CONVERT(varchar(100), GETDATE(), 0): 05 16 2006 10:57AM Select CON ...

最新文章

  1. 一文详尽2019全年AI技术突破
  2. python自学路线-零基础Python学习路线,小白的进阶之路!
  3. 用linux遇到的一个死循环
  4. Mysql:好好的索引,为什么要下推?
  5. WSDL SOAP 绑定
  6. [Java基础]复制文件的异常处理try...catch...finally的做法
  7. wso2 esb_使用WSO2 ESB进行邮件内容过滤
  8. ad中那个快捷键是重复上一部_Excel中的F4快捷键用的好,告别加班没烦恼!
  9. hdu4000 amp;amp; hrbust1625
  10. C#中你可能不知道的8件事(zz)
  11. cad安装日志文件发生错误_Autocad 2012 安装失败,某些产品无法安装。有日志文件,拜托求大神帮忙看看如何解决?...
  12. 如何设置内网端口映射外网
  13. BZOJ3709 Bohater 贪心
  14. JavaFX Scene Builder的使用
  15. 计算机网络基础学习笔记
  16. PMP(第六版)中的沟通方法
  17. 【附源码】计算机毕业设计JAVA医院病历管理系统
  18. D3.js v5.0 旭日图
  19. 42 《养育的选择》-豆瓣评分8.8
  20. H3C配置三层交换机配置实例

热门文章

  1. Atitit 多继承实现解决方案 java c#
  2. Atititjs javascript异常处理机制与java异常的转换.js exception process
  3. paip.刮刮卡砸金蛋抽奖概率算法跟核心流程.
  4. paip.提升用户体验--radio图片选择器 easyui 实现..
  5. paip.消除 Java 的冗长try/catch/finally
  6. paip.提升用户体验----gcc c++ 编译速度提升by预编译头技术 .doc
  7. paip.设置鼠标灵敏度API
  8. 王川: 重要的东西, 往往是看不见的
  9. (转)别只盯着比特币!“野蛮生长”的ICO江湖:2年30倍只是寻常
  10. 新兴IT企业特斯拉(四)——Model 3