由一個大寫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 編輯過 |
關鍵字查詢
相關文章
正在查詢... |