1 個需求,2 種寫法, 3 層境界
點擊藍(lán)色“有關(guān)SQL”關(guān)注我喲
加個“星標(biāo)”,天天與10000人一起快樂成長

圖 | L
1 個需求
外人看來一個簡單的需求:
把某個人的身份信息,合并到用戶表里。
思路再簡單不過:如果這個人存在表里,那就更新;如果他/她不在,那就新建。
2 種寫法
很多朋友,寫這類 SQL,手到擒來。無非就是 Update 和 Insert.
先判斷下這個人,在不在表里:
IF?Exists(SELECT?TOP?1?1?FROM?User?WHERE?UserName?=?@var_UserName)
BEIGN?
????UPDATE?User?SET?XXX?=?XXX?WHERE?UserName?=?@var_UserName
END
ELSE
BEGIN?
????INSERT?INTO?User?(?XXX,XXX)?)?VALUES(xxx,xxx)
END?
但,SQL 表達(dá)可以更簡單,請出今天的主角:Merge
MERGE?INTO?User
????USING?(xxx)?AS?UserUpdate
????on?User.UserName?=?UserUpdate.UserName
????WHEN?MATCHED?THEN?UPDATE?SET?UserAddress?=?UserUpdate.UserAddress
????WHEN?NOT?MATCHED?THEN?INSERT(XXX,XXX)?VALUES(xxx,xxx)
Merge 語句同樣實現(xiàn)了 UPDATE/INSERT 組合的功能。
解釋下:
USING(xxx) AS UserUpdate ON:
xxx 表示用來更新的準(zhǔn)備數(shù)據(jù),其形式可以是一條SELECT 語句,也可以是一條 VALUES構(gòu)造語句(適用于SQL Server)。
ON 在這里,指定了匹配條件
MATCHED:
當(dāng)匹配條件滿足,執(zhí)行數(shù)據(jù)更新
NOT MATCHED :
當(dāng)匹配條件不滿足,執(zhí)行數(shù)據(jù)新建
3 層境界
到這里還沒完。
能寫出第一類 UPDATE/INSERT 算是基礎(chǔ)過關(guān)。如果數(shù)據(jù)庫訪問量不大,自然沒毛病。
但,UPDATE/INSERT 并不安全。
如果在判斷 EXISTS 同時,該用戶被其他人新建,則會產(chǎn)生沖突。所以,加上 BEGIN TRANS 來發(fā)起事務(wù)控制,將其他用戶操作隔離開來。這是第二境界。
Merge 就不需要這份考量。它是一個語句,從語句層面完成了事務(wù)控制。
但 Merge 雖強,碰到大數(shù)據(jù)量,寫法依舊單薄。尤其在 Merge 操作中,更新了上百萬行,產(chǎn)生大量日志的同時,還會鎖表,對數(shù)據(jù)庫及其不友好。
怎么辦?改批次!
?
?MERGE?TOP(10000)?USER
??USING?(xxx)?AS?UserUpdate
????on?User.UserName?=?UserUpdate.UserName
????WHEN?MATCHED?THEN?UPDATE?SET?UserName?=?UserUpdate.UserName
????WHEN?NOT?MATCHED?THEN?INSERT(XXX,XXX)?VALUES(xxx,xxx)
?
每 10000 條數(shù)據(jù)做一次 Merge,可以完美解決。
這是第三層考量。
那,為什么要用 Merge 而不用 UPDATE/INSERT 組合呢?原因有 2:
Merge 單條語句實現(xiàn)了事務(wù)控制,上面已說 Merge 是輕量更新:本例用一條數(shù)據(jù)解釋了 Merge,但實際情況,Merge 可以實現(xiàn)表對表的合并,當(dāng)兩表數(shù)據(jù)量都大時, UPDATE/INSERT ?組合,產(chǎn)生了兩次對比查詢,和兩次日志更新,但 Merge 只需一次。
往期精彩:
