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

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS SQL Server,基础系列 2核4GB
简介: 其实这是一篇没有技术含量的文章,精通SQL优化的请绕道。这个缘起于在优化一个SQL过程中,同事问了我一个问题,为什么SQL中存在隐式转换,但是执行计划没有变? 我思索了一下,觉得这个问题也有点意思,说不定有些对隐式转换了解得不深入的同学都有此疑问,那么下面结合上下文场景做一个细节方面的解答。

其实这是一篇没有技术含量的文章,精通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开销还是有所区别的。

 

image

 

 

 

image

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
相关文章
|
6月前
|
SQL IDE Java
Java连接SQL Server数据库的详细操作流程
Java连接SQL Server数据库的详细操作流程
|
3月前
|
关系型数据库 MySQL 网络安全
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
|
5月前
|
SQL 存储 监控
SQL Server的并行实施如何优化?
【7月更文挑战第23天】SQL Server的并行实施如何优化?
129 13
|
5月前
|
SQL
解锁 SQL Server 2022的时间序列数据功能
【7月更文挑战第14天】要解锁SQL Server 2022的时间序列数据功能,可使用`generate_series`函数生成整数序列,例如:`SELECT value FROM generate_series(1, 10)。此外,`date_bucket`函数能按指定间隔(如周)对日期时间值分组,这些工具结合窗口函数和其他时间日期函数,能高效处理和分析时间序列数据。更多信息请参考官方文档和技术资料。
|
5月前
|
SQL 存储 网络安全
关系数据库SQLserver 安装 SQL Server
【7月更文挑战第26天】
69 6
|
5月前
|
存储 SQL C++
对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型
【7月更文挑战7天】SQL Server 中的 VARCHAR(max) vs VARCHAR(n): - VARCHAR(n) 存储最多 n 个字符(1-8000),适合短文本。 - VARCHAR(max) 可存储约 21 亿个字符,适合大量文本。 - VARCHAR(n) 在处理小数据时性能更好,空间固定。 - VARCHAR(max) 对于大文本更合适,但可能影响性能。 - 选择取决于数据长度预期和业务需求。
448 1
|
5月前
|
SQL Oracle 关系型数据库
MySQL、SQL Server和Oracle数据库安装部署教程
数据库的安装部署教程因不同的数据库管理系统(DBMS)而异,以下将以MySQL、SQL Server和Oracle为例,分别概述其安装部署的基本步骤。请注意,由于软件版本和操作系统的不同,具体步骤可能会有所变化。
367 3
|
4月前
|
SQL 安全 Java
驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。错误:“The server selected protocol version TLS10 is not accepted by client
驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。错误:“The server selected protocol version TLS10 is not accepted by client
528 0
|
5月前
|
SQL 存储 安全
数据库数据恢复—SQL Server数据库出现逻辑错误的数据恢复案例
SQL Server数据库数据恢复环境: 某品牌服务器存储中有两组raid5磁盘阵列。操作系统层面跑着SQL Server数据库,SQL Server数据库存放在D盘分区中。 SQL Server数据库故障: 存放SQL Server数据库的D盘分区容量不足,管理员在E盘中生成了一个.ndf的文件并且将数据库路径指向E盘继续使用。数据库继续运行一段时间后出现故障并报错,连接失效,SqlServer数据库无法附加查询。管理员多次尝试恢复数据库数据但是没有成功。
|
5月前
|
SQL 存储 关系型数据库
关系型数据库SQL Server学习
【7月更文挑战第4天】
84 2