1 个需求,2 种写法, 3 层境界

共 1729字,需浏览 4分钟

 ·

2021-01-21 10:18

点击蓝色“有关SQL”关注我哟

加个“星标”,天天与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 表达可以更简单,请出今天的主角: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 语句同样实现了 UPDATE/INSERT 组合的功能。

解释下:

  • USING(xxx) AS UserUpdate ON:

    xxx 表示用来更新的准备数据,其形式可以是一条SELECT 语句,也可以是一条 VALUES构造语句(适用于SQL Server)。

    ON 在这里,指定了匹配条件

  • MATCHED:

    当匹配条件满足,执行数据更新

  • NOT MATCHED :

    当匹配条件不满足,执行数据新建

3 层境界

到这里还没完。

能写出第一类 UPDATE/INSERT 算是基础过关。如果数据库访问量不大,自然没毛病。

但,UPDATE/INSERT 并不安全。

如果在判断 EXISTS 同时,该用户被其他人新建,则会产生冲突。所以,加上 BEGIN TRANS 来发起事务控制,将其他用户操作隔离开来。这是第二境界。

Merge 就不需要这份考量。它是一个语句,从语句层面完成了事务控制。

但 Merge 虽强,碰到大数据量,写法依旧单薄。尤其在 Merge 操作中,更新了上百万行,产生大量日志的同时,还会锁表,对数据库及其不友好。

怎么办?改批次!

 
 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 条数据做一次 Merge,可以完美解决。

这是第三层考量。

那,为什么要用 Merge 而不用 UPDATE/INSERT 组合呢?原因有 2:

  • Merge 单条语句实现了事务控制,上面已说
  • Merge 是轻量更新:本例用一条数据解释了 Merge,但实际情况,Merge 可以实现表对表的合并,当两表数据量都大时, UPDATE/INSERT  组合,产生了两次对比查询,和两次日志更新,但 Merge 只需一次。



--完--





往期精彩:


本号精华合集(三)

如何写好 5000 行的 SQL 代码

如何提高阅读 SQL 源代码的快感

我在面试数据库工程师候选人时,常问的一些题

零基础 SQL 数据库小白,从入门到精通的学习路线与书单










浏览 13
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报