SqlServer隱式轉換問題

2021-09-02 12:15:54 字數 3100 閱讀 7172

在sql server的應用開發過程(尤其是二次開發)中可能由於開發人員對錶的結構不夠了解,造成開發過程中使用了不合理的方式造成資料庫引擎未按預定執行,以致影響業務.這是非常值得注意的.這次為大家介紹由於隱式資料型別轉換而造成的死鎖及相應解決方案.

現實中有些程式設計師/資料庫開發者會根據資料庫的處理機制實現一些應用,如搶座應用,可能會對事務中的查詢加一些列的hint以細化粒度,實現應用的同時使得影響最低,但也有可能因為一些小細節的欠缺而引發錯誤,從而造成糟糕的使用者體驗.如下面這個例子

生成測試資料

code

create

table

testlock

(id

varchar(10) primary

keyclustered

,col1

varchar(20

),col2

char(200

))go

----------create test table

declare

@iint

set@i=1

while

@i<

100begin

insert

into

testlock

select

right(replicate('

0',10)+

cast(@i

asvarchar(10)),10),'

aaa','

fixchar

'set@i=

@i+1end

go--

--------generate test data

此時我們開啟trace profiler 跟蹤死鎖相關資訊

然後分別在兩個session中執行如下語句

code

declare

@idnvarchar(10

)begin

tran

select

top1

@id= id from testlock with

(updlock, rowlock, readpast)

where col1 =

'aaa

'order

by id asc

select

@idwaitfor delay '

00:00:20

'update testlock set col1 =

'bbb

'where id =

@idcommit

tran

大約20s後我們可以從trace 中捕捉到死鎖了如圖1-1

圖1-1

問題分析

從死鎖圖中看既然更新既然擁有了自己的鍵鎖為何要其它會話的呢?很明顯,可能期望的鎖粒度擴大了.

進而分析任意乙個會話的執行計畫語句發現了異常,最後的更新出現了隱式資料型別轉換,以至於做了額外的聚集表掃瞄過程,致使執行更新過程需要所有鍵的u鎖,從而引發了死鎖.

如圖1-2

圖1-2

而表testlock中id的定義是varchar(10) 問題就出在這裡.

這裡介紹乙個小的知識點:資料型別優先順序

當運算子表示式中資料型別不同時,按照型別的優先順序低優先順序的向高優先順序的資料型別轉換.當然如果兩個資料型別不支援隱式轉換則失敗報錯.

通過資料型別優先順序列表發現nvarchar是高於varchar的,所以varchar將向nvarchar轉換,進而使優化器選擇了意料之外的執行計畫,從而引發了死鎖

如圖1-3

圖1-3

詳細參考

解決 找到問題的根源了,解決起來也就簡單了,我們只需將查詢中定義的declare @id nvarchar(10)

調整為varchar即可(甚至char,通過優先順序列表可知,char低於varchar.)

code

declare

@idvarchar(10

)begin

tran

select

top1

@id= id from testlock with

(updlock, rowlock, readpast)

where col1 =

'aaa

'order

by id asc

select

@idwaitfor delay '

00:00:20

'update testlock set col1 =

'bbb

'where id =

@idcommit

tran

我們可以看到相應的執行計畫發生了改變,我們期待的執行計畫出現了.如圖1-4

圖1-4

至此,問題解決.

注意:雖然有資料優先順序,但建議大家在做開發時,定義的變數要與目標表的資料型別一致,從根源上避免隱式轉換.

結語:乙個小小的字元當真是可以引發血案,在做應用開發中我們需要知道每個字元的深刻含義.

後記:部落格內容發表後有熱心的朋友@yaoquan.luo,@victor596,@uestc小田,@sonnyxue 測試發現在sql2008r2中並未有死鎖出現,由此給大家帶來的困惑深表歉意.這裡為大家解釋下原因

sql server優化器特性-動態檢索

有陣子沒寫部落格了,家裡有個小孩,目前時間不算充裕,但我會堅持下去的,各位的同學的支援就是我的動力!最後給大家拜個早年,祝大家羊年大吉,錢途無量!

scala 隱式轉換函式 隱式轉換引數

目前的scala相關部落格大概只能算乙個筆記,方便自己記錄,也幫大家查詢資訊了。首先scala中的隱式轉換可以分為隱式函式轉換與隱式引數轉換兩類,下面就來分別說一下自己對這兩種模式的理解。1 隱式函式轉換,我們先看一段 scala val x int 3.14 10 error type misma...

隱式轉換和隱式引數

1 隱式轉換 隱式轉換函式是以implicit關鍵字宣告的帶有單個引數的函式。這種函式將會自動應用,將值從一種型別轉換為另一種型別 object scala01 implicit def f1 d double int double 是輸入型別,int 是轉換後的型別 隱式函式的底層工作原理 def...

mysql 隱式轉換 mysql中的隱式轉換

在mysql查詢中,當查詢條件左右兩側型別不匹配的時候會發生隱式轉換,可能導致查詢無法使用索引。下面分析兩種隱式轉換的情況 看表結構 phone為 int型別,name為 varchar 兩種情況都可以用到索引,這次等號右側是 2 注意帶單引號喲,左側的索引欄位是int型別,因此也會發生隱式轉換,但...