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