如何在SQL中有效地“合并”两个表?

时间:2014-08-24 19:07:48

标签: sql postgresql postgresql-9.3

我有两张表(例如' foo'和' bar'),结构相同,主键(例如' a'):

CREATE TABLE foo(a INT PRIMARY KEY, b VARCHAR(10));
INSERT INTO foo(a, b) VALUES (1, 'foo'), (2, 'foo');
CREATE TABLE bar(a INT PRIMARY KEY, b VARCHAR(10));
INSERT INTO bar(a, b) VALUES (2, 'bar'), (3, 'bar');

现在我想更新表格的行' foo'使用表格中的行值' bar'主键匹配的位置,我想插入表中的行' bar'进入表格#foo'如果主要密钥在表格中已经不存在,那就是:

UPDATE foo SET b = bar.b FROM bar WHERE foo.a = bar.a;
INSERT INTO foo SELECT bar.* FROM bar LEFT JOIN foo USING (a) WHERE foo.a IS NULL;

这就是我想要的,但我想知道是否有更有效的方法来做到这一点?

1 个答案:

答案 0 :(得分:1)

如果其他人不同时访问您的表,您可以使用FULL [OUTER] JOIN查询创建一个新的合并表,其中bar的值优先。

如果你有并发访问权限,但能够锁定这两个表,那也是有效的:

BEGIN;
LOCK foo, bar;                     -- if you need it

CREATE TABLE baz AS
SELECT a, COALESCE(b.b, a.b) AS b  -- bar gets priority
FROM   foo f
FULL   JOIN bar b USING (a)
ORDER  BY a;                       -- optional order by

-- you need table name foo?
DROP  TABLE foo, bar;
ALTER TABLE baz RENAME TO foo;
ALTER TABLE foo ADD CONSTRAINT foo_a_pkey PRIMARY KEY (a);
-- do more?

COMMIT;

如果你有大量的重叠,那么编写一个没有死行的新的原始(集群)表比更新大部分旧表更有效。如果重叠不大,则更新/插入可能更有效。如果两个表都很小,请不要打扰并使用简单的解决方案。

新表显然没有旧表的任何索引或约束。重新创造你需要的东西。

如果你有很多依赖对象(视图,函数),你可能想要保留旧表。而是创建临时表TRUNCATE foo并将数据写回到同一个表中。这也不会杀死等待现有表的并发事务。

BEGIN;
LOCK foo, bar;                     -- if you need it

SET temp_buffers = 500MB;          -- if you need it

CREATE TEMP TABLE tmp AS
SELECT a, COALESCE(b.b, a.b) AS b  -- bar gets priority
FROM   foo f
FULL   JOIN bar b USING (a);

-- for performance, you might want to drop indexes and constraints here ...
TRUNCATE foo;
INSERT INTO foo
SELECT * FROM tmp
ORDER BY a;                         -- optional

DROP  TABLE  bar;                   -- optional
-- ... and recreate previously dropped indexes and constraints here

COMMIT;

关于temp_buffers

并发写入会发生什么?