由一個大寫N造成的SQL Server死鎖
當(dāng)前位置:點晴教程→知識管理交流
→『 技術(shù)文檔交流 』
SQL Server死鎖的問題斷斷續(xù)續(xù)追蹤了兩三個星期,終于有個初步的判斷:有一個SELECT語句和一個UPDATE語句需要獲取大量的鎖。死鎖應(yīng)該與之相關(guān)。 應(yīng)用程序在SQL中為每個傳入的字符串參數(shù)加了N,表示是unicode字符串。在參數(shù)與相應(yīng)的列進行匹配的時候,如果該列不是NVARCHAR而是VARCHAR類型,則SQL Server要對該列的數(shù)據(jù)進行轉(zhuǎn)換,由于此轉(zhuǎn)換而導(dǎo)致不能使用索引,會獲取大量的鍵鎖、頁鎖。如果幾個這樣的SQL同時執(zhí)行則容易死鎖。 比如這樣幾句SQL:
這是用事件探查器跟蹤到的。 其中只有SELECT....是在java應(yīng)用中寫的SQL,前面的declare、set、exec以及后面的select @P1都應(yīng)該是jdbc生成的。declare @P1 int聲明了一個int變量P1,set @P!=NULL 把P1賦值為空,exec sp_prepexec ....是執(zhí)行SQL Server的存儲過程sp_prepexec。@P1是一個輸出參數(shù),在存儲過程執(zhí)行后,P1會得到SQL Server分配的句柄。之后就可以用exec sp_execute引用這個句柄來再次執(zhí)行此SQL。比如:
這就是執(zhí)行一個前面已分配句柄的SQL,句柄是450,后面是SQL中需要使用的參數(shù)。 好,現(xiàn)在說N。前面的幾個SQL中可以看到在字符串參數(shù)值的前面有一個大寫的N,它的含義是表明后面引號里的字符串是unicode,如果我沒判斷錯的話,應(yīng)該就是UTF-8。 為什么能判斷出有了這個N之后就會獲取大量的鎖呢?是借助于查詢分析器。 我把以下SQL貼到查詢分析器中
然后“顯示估計的查詢計劃”在CMDOCUMENTS.PK_...中看到對全部的索引做了掃描(scan),還有“成本100%”,并且其中“參數(shù):”一欄的內(nèi)容引起了我的懷疑,內(nèi)容如下:
可以看到WHERE后面有對列DOCID使用了個函數(shù)convert,一般的數(shù)據(jù)庫,如果一旦對列使用了函數(shù)就無法使用建立在該列上的索引,除非建立的是函數(shù)索引。 看表結(jié)構(gòu),DOCID是VARCHAR類型的。 把N去掉,再做分析
仍然是“成本100%”,但是convert不見了。 使用事件探查器跟蹤。有N的情況下,此查詢會獲取大量的鎖。沒有N的情況下,只獲取非常少量的鎖。如果不去掉N,但把DOCID改為NVARCHAR類型,查詢也不會獲取大量的鎖。所以在SQL Server中使用N可要慎重。 該文章在 2010/12/25 21:47:05 編輯過 |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |