微軟Sql server的Update語句,有個不錯的擴展功能,通過允許變量賦值,可在語句中嵌入復雜的邏輯計算,從而讓本來需要一個Select 加一個Update語句的段子,被優化成只需一個update語句。這對性能提高有不小的好處.但是,這項功能有個尚未報告且不易注意的bug.
舉例來說,下述形式都是合法的:
Update table1 set column1 = expr1, @var1 = expr2, @var2= column2 = expr3, ... where where_condition
為了說更透徹的說明問題, 看下面的語句:
UPDATE dbo.TableX SET @oldDesc = Description, @OldApr = ApproveBits, @NewApr = case when @OldApr & @txtCheck <> 0 and @oldDesc <> @Description then @OldApr & @txtMask2 else @OldApr end, @NewApr = (case when @NewApr & @rateCheck = 0 then @NewApr when @protectlevel >= XRate then @NewApr | @rateBit else @NewApr & @rateMask end), ApproveBits = @NewApr, --don't as @NewApr=ApproveBits= -- parse incorrectly due to a bug @dateSet = case when LastModified is null and (@NewApr = 0 or @NewApr = 3) then 1 else 0 end, LastModified = case when @dateSet = 1 then @pnewDate else LastModified end,... WHERE ...
你看了上面的代碼會不會暈?
. 在Update Clause中, 標准的sql只允許對數據庫表的列賦值.由於微軟sql的這一擴展, 允許對變量賦值, 再和case 語句組合起來, 就可以實現相當復雜的邏輯計算.如果沒有這些,一個Update語句就能做完的事情,就需要一個Select加一個Update語句才能實現.上面的那個例子,全面的利用了這一功能,從而實現對性能的提高和優化.
你如果看到上面的代碼會暈,那是因為,微軟本身提供的文檔並沒有完整透徹的說明這一功能,經過我個人的測試和總結,補充以下重要條款:
1.由於允許被賦值的是變量,可以在update中嵌入復雜的邏輯計算,並且可以讓本來需要一個select 加一個update語句的段子,被優化成只需要一個update語句的段子。這對性能提高有不小的好處。
2。@var2= column2 = expr3, 等同於: @var2= expr3, column2 = expr3
不同於“@var2= column2, column2 = expr3" 或者“column2 = expr3, @var2= column2", 后兩種形式都是把column2的舊值賦予了@var2.
3. 形式: column2 = @var2= expr3, 非法.
由於可能出現嵌套引用,所以必須知道在賦值時的優先級,規則如下,
4. 變量賦值相對列賦值優先.
5. 如果都是變量賦值,那么更靠左邊的優先.
6. 在賦值表達式右邊出現的變量的值是該變量的當前值.
7. 在賦值表達式右邊出現的列的值永遠是該列的舊值, 與在update語句中的次序無關.
目前, 這個擴展功能有一個bug, 就是,在下面的形式中:
"...set @var2 = expr1, @var2= column2 = expr2,... ",
你會想當然地認為@var2最后的值是expr2, 但是,由於這個bug,實際上, var2最后的值是expr1.
為了繞開這個bug, 你可以把上面重寫成下面的形式:
@var2 = expr1, @var2= expr2, column2 = @var2
這里介紹的都是個人精煉的,在微軟的文獻中找不到的,值得收藏呵.
weibo:JohnXhark
