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

现实中有些程序员/数据库开发者会根据数据库的处理机制实现一些应用,如抢座应用,可能会对事务中的查询加一些列的Hint以细化粒度,实现应用的同时使得影响最低,但也有可能因为一些小细节的欠缺而引发错误,从而造成糟糕的用户体验.如下面这个例子

生成测试数据

code

01.create table testlock
02.(ID varchar(10) primary key clustered,
03.col1 varchar(20),
04.col2 char(200))
05.go----------create test table
06. 
07.declare @i int
08.set @i = 1
09.while @i < 100
10.begin
11.insert into testlock
12.select right(replicate('0',10)+ cast(@i as varchar(10)),10),'aaa','fixchar'
13.set @i = @i+1
14.end
15.go----------generate test data

此时我们打开trace profiler 跟踪死锁相关信息

然后分别在两个session中运行如下语句

code

01.declare @ID nvarchar(10)
02. 
03.begin tran 
04. 
05.select  top 1 @ID = ID from testlock with(updlock, rowlock, readpast)
06.where col1 = 'aaa'
07.order by id asc
08. 
09.select  @ID
10. 
11.waitfor delay '00:00:20'
12. 
13.update testlock set col1 = 'bbb' where id = @ID
14. 
15.commit tran

大约20s后我们可以从trace 中捕捉到死锁了如图1-1

问题分析

从死锁图中看既然更新既然拥有了自己的键锁为何要其它会话的呢?很明显,可能期望的锁粒度扩大了.

进而分析任意一个会话的执行计划语句发现了异常,最后的更新出现了隐式数据类型转换,以至于做了额外的聚集表扫描过程,致使执行更新过程需要所有键的U锁,从而引发了死锁.

如图1-2

为什么会出现隐式转换呢,通过检查执行的代码发现"declare @ID nvarchar(10)"

而表testlock中ID的定义是varchar(10) 问题就出在这里.

这里介绍一个小的知识点:数据类型优先级

当运算符表达式中数据类型不同时,按照类型的优先级低优先级的向高优先级的数据类型转换.当然如果两个数据类型不支持隐式转换则失败报错.

通过数据类型优先级列表发现nvarchar是高于varchar的,所以varchar将向nvarchar转换,进而使优化器选择了意料之外的执行计划,从而引发了死锁

如图1-3

详细参考

https://msdn.microsoft.com/zh-cn/library/ms190309.aspx

解决

找到问题的根源了,解决起来也就简单了,我们只需将查询中定义的declare @ID nvarchar(10)

调整为varchar即可(甚至char,通过优先级列表可知,char低于varchar.)

code

01.declare @ID varchar(10)
02. 
03.begin tran 
04. 
05.select  top 1 @ID = ID from testlock with(updlock, rowlock, readpast)
06.where col1 = 'aaa'
07.order by id asc
08. 
09.select  @ID
10. 
11.waitfor delay '00:00:20'
12. 
13.update testlock set col1 = 'bbb' where id = @ID
14. 
15.commit tran

我们可以看到相应的执行计划发生了改变,我们期待的执行计划出现了.如图1-4

至此,问题解决.

注意:虽然有数据优先级,但建议大家在做开发时,定义的变量要与目标表的数据类型一致,从根源上避免隐式转换.

结语:一个小小的字符当真是可以引发血案,在做应用开发中我们需要知道每个字符的深刻含义.

SQL Server 隐式转换引发的死锁的更多相关文章

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

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

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

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

  3. SQL Server中提前找到隐式转换提升性能的办法

        http://www.cnblogs.com/shanksgao/p/4254942.html 高兄这篇文章很好的谈论了由于数据隐式转换造成执行计划不准确,从而造成了死锁.那如果在事情出现之前 ...

  4. 【转】SQL SERVER标量表达式的隐式转换

    在SQL Server中的数据类型中,存在着优先级的问题.标量表达示的返回结果类型也会根据操作数的类型而定,如1 +'1'=2.而不是'11',因些Int型的优先级比VARCHAR型的优先级要高.所以 ...

  5. SQL Server有意思的数据类型隐式转换问题

    写这篇文章的时候,还真不知道如何取名,也不知道这个该如何将其归类.这个是同事遇到的一个案例,案例比较复杂,这里抽丝剥茧,仅仅构造一个简单的案例来展现一下这个问题.我们先构造测试数据,如下所示: CRE ...

  6. SQL Server ->> 数据类型不一致比较时的隐式转换

    当使用操作符进行比较的时候,两边数据类型不一致的情况下,数据类型优先级别低的会往优先级别高的发生隐式转换.下面的参考链接是优先级别列表. 参考: Data Type Precedence (Trans ...

  7. 数栈SQL优化案例:隐式转换

    MySQL是当下最流行的关系型数据库之一,互联网高速发展的今天,MySQL数据库在电商.金融等诸多行业的生产系统中被广泛使用. 在实际的开发运维过程中,想必大家也常常会碰到慢SQL的困扰.一条性能不好 ...

  8. MySQL SQL优化之字符串索引隐式转换

    之前有用户很不解:SQL语句非常简单,就是select * from test_1 where user_id=1 这种类型,而且user_id上已经建立索引了,怎么还是查询很慢? test_1的表结 ...

  9. C++ 构造函数 隐式转换 深度探索,由‘类对象的赋值操作是否有可能调用到构造函数’该实验现象引发

    Test1 /** Ques: 类对象的赋值操作是否有可能调用到构造函数 ? **/ class mystring { char str[100]; public: mystring() //myst ...

随机推荐

  1. MySQL数据库篇之多表查询

    主要内容: 一.多表连接查询 二.复合条件连接查询 三.子查询 1️⃣  多表连接查询 一.准备表 #建表 create table department( id int, name varchar( ...

  2. Callable接口使用以及计算斐波那契数字的数值总和

    一.简单使用 Runnable是执行工作的独立任务,但是它不返回任何值.如果你希望任务完成的时能够返回一个值,那么可以实现一个Callable接口.在Java SE5中引入的Callable是一种具有 ...

  3. Kibana(elasticsearch操作工具)的安装

    在安装完es集群的基础上 1.创建文件夹并赋权 # 使用root进行操作 mkdir -p /export/data/kibana mkdir -p /export/logs/kibana # 赋权给 ...

  4. Android中自定义ListView实现上拉加载更多和下拉刷新

    ListView是Android中一个功能强大而且很常用的控件,在很多App中都有ListView的下拉刷新数据和上拉加载更多这个功能.这里我就简单记录一下实现过程. 实现这个功能的方法不止一个,Gi ...

  5. spring MVC模式拦截所有入口方法的入参出参打印

    import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.serializer.SerializerFeature; im ...

  6. emulator: Trying to vcpu execute at eip:6d4053

  7. Node.js简介(转)

    目前,Node.js是在前端页面开发中十分受欢迎的,它是一套用来编写高性能网络服务器的JavaScript工具包,在本文中,将带领各位初学者介绍Node JS的基本知识,要求本文的阅读对象为有一定Ja ...

  8. linux系统如何更改文件权限

    一. 更改文件9个属性:chmod 用这个命令修改文件属性有两种方式:数字或者符号 1. 数字类型改变文件权限 chmod (1)类unix系统的文件有9个属性分别是owner/group/other ...

  9. SQL Compare数据库版本比较工具

    Red Gate系列文章: Red Gate系列之一 SQL Compare 10.4.8.87 Edition 数据库比较工具 完全破解+使用教程 Red Gate系列之二 SQL Source C ...

  10. Openssl enc命令

    一.简介 enc - 对称加密例程,使用对称密钥对数据进行加解密,特点是速度快,能对大量数据进行处理.算法有流算法和分组加密算法,流算法是逐字节加,由于其容易被破译,现在已很少使用:分组加密算法是将数 ...