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

有关SQL

共 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
点赞
评论
收藏
分享

手机扫一扫分享

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

手机扫一扫分享

举报