https://www.cnblogs.com/kerrycode/p/5853257.html

其实这是一篇没有技术含量的文章,精通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中隐式转换的一些细节浅析

    其实这是一篇没有技术含量的文章,精通SQL优化的请绕道.这个缘起于在优化一个SQL过程中,同事问了我一个问题,为什么SQL中存在隐式转换,但是执行计划没有变? 我思索了一下,觉得这个问题也有点意思,说 ...

  2. SQL Server 隐式转换引发的躺枪死锁-程序员需知

    在SQL Server的应用开发过程(尤其是二次开发)中可能由于开发人员对表的结构不够了解,造成开发过程中使用了不合理的方式造成数据库引擎未按预定执行,以致影响业务.这是非常值得注意的.这次为大家介绍 ...

  3. SQL Server 隐式转换引发的死锁

    在SQL Server的应用开发过程(尤其是二次开发)中可能由于开发人员对表的结构不够了解,造成开发过程中使用了不合理的方式造成数据库引擎未按预定执行,以致影响业务.这是非常值得注意的.这次为大家介绍 ...

  4. SQL Server中行列转换 Pivot UnPivot

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

  5. SQL Server全时区转换

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

  6. piap.excel 微软 时间戳转换mssql sql server文件时间戳转换unix 导入mysql

    piap.excel 微软 时间戳转换mssql sql server文件时间戳转换unix 导入mysql 需要不个mssql的sql文件导入mysql.他们的时间戳格式不同..ms用的是自定义的时 ...

  7. Scala 深入浅出实战经典 第65讲:Scala中隐式转换内幕揭秘、最佳实践及其在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  8. sql server动态行列转换

    原文链接:https://www.cnblogs.com/gaizai/p/3753296.html sql server动态行列转换 一.本文所涉及的内容(Contents) 本文所涉及的内容(Co ...

  9. SQL Server中datetimeset转换datetime类型问题浅析

    在SQL Server中,数据类型datetimeoffset转换为datetime类型或datetime2类型时需要特别注意,有可能一不小心你可能会碰到下面这种情况.下面我们构造一个简单案例,模拟一 ...

  10. SQL Server 进制转换函数

    一.背景 前段时间群里的朋友问了一个问题:“在查询时增加一个递增序列,如:0x00000001,即每一个都是36进位(0—9,A--Z),0x0000000Z后面将是0x00000010,生成一个像下 ...

随机推荐

  1. Windows 7更新失败的解决方法

    你好,1.在开始菜单中点击运行,→输入"services.msc"→找到"windows update"右击选择"停止":2.进入C:\wi ...

  2. 在线编辑Excel——插入图表

    本文内容介绍如何通过Excel在线编辑器--Spire.Cloud Excel来实现图表插入,插入图表时,可插入常见的柱状图.饼图.折线图.条形图.面积图.散点图.股价图等.这里挑选几种图表来展示插入 ...

  3. PanGu-Coder:函数级的代码生成模型

    摘要:华为诺亚方舟实验室语音语义实验室联合华为云PaaS技术创新实验室基于PanGu-Alpha研制出了当前业界最新的模型PanGu-Coder 本文分享自华为云社区<PanGu-Coder 函 ...

  4. Mapper that could not be found

    现象1 mapper 资源扫不到 resources 建的是 目录 ,不是 package 所以如果直接 a.b 的方式创建,会扫描不到 mapper.xml 文件 现象2 缺少配置文件 HisDru ...

  5. MongoDB 副本模式,会映射到本地 127.0.0.1 错误

    基于 MongoDB 读写分离--Windows MongoDB 副本集配置 ,里面配置了一个坑,导致出现下列错误 [2021-05-10 10:06:11.981] [cluster-Cluster ...

  6. MongoDB 内存占用过大

    不同的版本配置项可能不同:本文使用的 mongodb-win32-x86_64-2012plus-4.2.11-signed.msi mongod.cfg  默认占用内存为 0.5*(物理内存-1)如 ...

  7. 在Flutter中使用SetState无效?可能是忽略了这个!

    这次是Flutter开发技术分享,解决的问题点来自本人实际的开发经历. 首先描述一下问题:在某个组件中调用setState()方法更新该组件状态,结果是无法做到更新效果,组件仍然维持原状. 下面我们用 ...

  8. PS CJ20N 项目定义属性字段增强

    一.CJ20N添加字段  二.用户出口  三.校验必输项 博客频遭盗窃,请移步公众号"斌将军",输入关键字"项目定义字段增强"查看 TRANSLATE with ...

  9. 【OpenSSL】​Visual Studio 2019配置OpenSSL 3.0开发环境

    OpenSSL从1.0.2版本升级为3.0.3版本后,需要对代码进行重构.如果不可用的代码太多,需要重新开一个项目.重新配置开发环境. [第一步]登录http://slproweb.com/,下载Wi ...

  10. JSP | out 对象详解

    原作者为 RioTian@cnblogs, 本作品采用 CC 4.0 BY 进行许可,转载请注明出处. 本篇学习自:C语言中文网,部分内容转载仅供学习使用. \[QAQ \] out 对象是一个输出流 ...