暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

使用 MERGE 让你的 PostgreSQL 更强大

原创 小小亮 2022-11-18
1810

MERGE 是在 PostgreSQL 版本 15 中引入的,它将对您编写查询的方式产生重大影响。这肯定会改变您处理事务日志和其他类似更新的方式。

想象一下,你有一个现有的表格,里面装满了有用的数据,比如你公司销售的商品库存,你会不时地得到数据集,其中包含需要输入的新产品或可能有也可能没有的库存列表。新数量的手头货物。这通常是您在应用程序中必须完成的工作类型。使用应用程序执行此操作的问题是数据必须来回移动,可能多次,从数据库到应用程序,这是很多开销(在这种情况下发音为“时间”) . 所以现在所有这些工作都可以在数据库服务器上用一个命令完成。

SQL Server 和 Oracle 都有这个运算符,它已经成为 SQL 标准的一部分已有一段时间了,PostgreSQL 最近在版本 15 中添加了它。您可以在一个语句中执行 INSERT、UPDATE 和 DELETE。虽然语法看起来有点复杂,但它远远超出了您很快就会看到的简单“upsert”。

术语

我们将有两个表要用 MERGE 处理。具有更新的表称为源表,数据的主要存储库称为目标表。将源表的内容与目标表进行比较,并对目标表进行操作。行被认为在两个表之间匹配或不匹配,并且对这些匹配采取相应的操作。

工作原理示例
让我们从两个表和一行数据开始。

test=# create table a (id int, x int, status char(10));
CREATE TABLE
test=# create table b (id int, x int, status char(10));
CREATE TABLE
test=# insert into a (id,x,status) values (1,1,'From a');
INSERT 0 1
test=# select * from a;select * from b;
id | x | status
----+---+------------
1 | 1 | From a
(1 row)

id | x | status
----+---+--------
(0 rows)

现在我们可以在查询中使用 MERGE。请记住,当您查看下面的查询时,表 a有一行数据而表 b没有任何数据行。在此查询中,我们插入不在目标表中的记录并更新那些在目标表中的记录。

Shell
MERGE into b using a on a.id = b.id
when matched then 
     update set x = b.x + 1
when not matched then 
     insert (id,x,status) values (a.id,a.x,a.status);

该查询指示服务器在 id 列上匹配两个表。如果有匹配的行,则表 b中的列x递增 1。但是,如果没有匹配项(因为表 b为空,所以不会有匹配项),那么表 a中行的内容将复制到表 b中。

如果我们明确地查看两个表的内容,我们会发现这两个表现在是相同的。

test=# select * from a; select * from b;
 id | x |   status
----+---+------------
  1 | 1 | From a
(1 row)


 id | x |   status
----+---+------------
  1 | 1 | From a
(1 row)

如果我们在查询中使用 EXPLAIN,我们会得到以下结果:

test-# update set x = b.x + 1
test-# when not matched then insert (id,x,status) values (a.id,a.x,a.status);
                           QUERY PLAN
----------------------------------------------------------------
 Merge on b  (cost=0.00..1.02 rows=0 width=0)
   ->  Nested Loop Left Join  (cost=0.00..1.02 rows=1 width=25)
         Join Filter: (a.id = b.id)
         ->  Seq Scan on a  (cost=0.00..1.01 rows=1 width=19)
         ->  Seq Scan on b  (cost=0.00..0.00 rows=1 width=10)
(5 rows)


test=#

并注意更新行需要是update set x = bx +1而不是update set bx =bx + 1因为它会触发语法错误。另外,您不能更新表 a – 只能更新目标表。

再次运行 MERGE

现在再次运行 MERGE 查询并查看两个表的内容。这次执行了匹配的逻辑,x 列的值从 1 增加到 2。

test=# select * from a; select * from b;
id | x | status
----+---+------------
1 | 1 | From a
(1 row)


id | x | status
----+---+------------
1 | 2 | From a
(1 row)


test=#

是的,每次我们重新运行 MERGE 查询时,列 x 都会递增。

删除!

如果找到匹配的行,DELETE 将从目标表 b中删除行。让我们更改查询,而不是增加列的值,我们只删除目标表中的匹配行。

test=# merge into b using a on a.id = b.id
test-# when matched then delete
test-# when not matched then insert (id,x,status) values (a.id,a.x,a.status);
MERGE 1
test=# select * from b;
 id | x | status
----+---+--------
(0 rows)

什么也不做

我们的选择之一是什么都不做。是的,我们发现该记录已经存在于源表中,因此可以跳过它。目前,表 b 在 DELETE 示例之后没有任何内容。因此,运行以下查询以填充表,然后再次运行。

test=# MERGE into b using a on a.id = b.id
test-# when matched then
test-#    DO NOTHING
test-# when not matched then
test-#    insert (id,x,status) values (a.id,a.x,a.status);
MERGE 1
test=#

太复杂了!

您可以根据需要使 MERGE 变得尽可能复杂。在下文中,您将看到我们可以对目标表的列的不同值进行操作。我们首先截断目标表,然后对第一个流行表 b 运行 MERGE 查询。然后我们第二次运行它并注意x和状态列的变化情况。当第三次运行 MERGE 查询时,列将再次更新。

test=# truncate b;
TRUNCATE TABLE
test=# select * from b;
 id | x | status
----+---+--------
(0 rows)
merge into b
using a
on b.id = a.id
when matched AND b.x > 2 THEN
UPDATE SET x = b.x + a.x, status='updated+'
when matched and b.x = 1 THEN
UPDATE SET status = 'updated', x = 3
when not matched then
insert (id,x,status) values (a.id,a.x,a.status);

现在运行 MERGE 查询一次。

test=# select * from b;
 id | x |   status
----+---+------------
  1 | 1 | From a
(1 row)

现在再次运行它。

test=# select * from b;
 id | x |   status
----+---+------------
  1 | 3 | updated
(1 row)

现在是第三次!

test=# select * from b;
 id | x |   status
----+---+------------
  1 | 4 | updated+
(1 row)

逻辑可以像你能忍受的那样复杂。

结论

MERGE 非常强大,即使是这些非常简单的示例也可以让您瞥见它的用法。许多年前,我正在从事一个项目,该项目具有来自世界各地收银机的交易日志,这些交易日志必须合并,如果 MERGE 可用,它将被大量使用。通读文档和本博客,我相信您会开始思考一些更常见的查询,以及它们如何从 MERGE 运算符中获益。

随着您的表变大,请务必仔细检查您是否在正确的列上使用索引并使用 EXPLAIN 进行仔细检查。

原文标题:Using MERGE To Make Your PostgreSQL More Powerful
原文作者:David Stokes
原文链接:https://www.percona.com/blog/using-merge-to-make-your-postgresql-more-powerful/

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论