由一个大写N造成的SQL Server死锁
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
SQL Server死锁的问题断断续续追踪了两三个星期,终于有个初步的判断:有一个SELECT语句和一个UPDATE语句需要获取大量的锁。死锁应该与之相关。 应用程序在SQL中为每个传入的字符串参数加了N,表示是unicode字符串。在参数与相应的列进行匹配的时候,如果该列不是NVARCHAR而是VARCHAR类型,则SQL Server要对该列的数据进行转换,由于此转换而导致不能使用索引,会获取大量的键锁、页锁。如果几个这样的SQL同时执行则容易死锁。 比如这样几句SQL:
这是用事件探查器跟踪到的。 其中只有SELECT....是在java应用中写的SQL,前面的declare、set、exec以及后面的select @P1都应该是jdbc生成的。declare @P1 int声明了一个int变量P1,set @P!=NULL 把P1赋值为空,exec sp_prepexec ....是执行SQL Server的存储过程sp_prepexec。@P1是一个输出参数,在存储过程执行后,P1会得到SQL Server分配的句柄。之后就可以用exec sp_execute引用这个句柄来再次执行此SQL。比如:
这就是执行一个前面已分配句柄的SQL,句柄是450,后面是SQL中需要使用的参数。 好,现在说N。前面的几个SQL中可以看到在字符串参数值的前面有一个大写的N,它的含义是表明后面引号里的字符串是unicode,如果我没判断错的话,应该就是UTF-8。 为什么能判断出有了这个N之后就会获取大量的锁呢?是借助于查询分析器。 我把以下SQL贴到查询分析器中
然后“显示估计的查询计划”在CMDOCUMENTS.PK_...中看到对全部的索引做了扫描(scan),还有“成本100%”,并且其中“参数:”一栏的内容引起了我的怀疑,内容如下:
可以看到WHERE后面有对列DOCID使用了个函数convert,一般的数据库,如果一旦对列使用了函数就无法使用建立在该列上的索引,除非建立的是函数索引。 看表结构,DOCID是VARCHAR类型的。 把N去掉,再做分析
仍然是“成本100%”,但是convert不见了。 使用事件探查器跟踪。有N的情况下,此查询会获取大量的锁。没有N的情况下,只获取非常少量的锁。如果不去掉N,但把DOCID改为NVARCHAR类型,查询也不会获取大量的锁。所以在SQL Server中使用N可要慎重。 该文章在 2010/12/25 21:47:05 编辑过 |
关键字查询
相关文章
正在查询... |