我要将值从一个表复制到另一个表(相同的表格方案)。什么是更好的(性能):
更新: 我在桌子上进行了一次小测试,排了近3k行。 删除和创建提供大约60毫秒与删除和插入 - 约30毫秒。
答案 0 :(得分:14)
我看到了四种有用的方法来替换表的内容。它们都不是“明显正确”,但这取决于您的要求。
(在单笔交易中)DELETE FROM foo; INSERT INTO foo SELECT ...
Pro:最佳并发:不会锁定访问该表的其他事务,因为它利用了Postgres的MVCC。
Con:如果单独测量插入速度,可能是最慢的。导致autovacuum清理死行,从而产生更高的I / O负载。
TRUNCATE foo; INSERT INTO foo SELECT ...
专业版:小表最快。写入I / O少于#1
Con:排除所有其他读者 - 从表中读取的其他交易必须等待。
TRUNCATE foo
,DROP表上的所有索引INSERT INTO foo SELECT ...
,重新创建所有索引。
Pro:对于大型表来说最快,因为使用CREATE INDEX
创建索引比以递增方式更新索引要快。
Con:与#2相同
切换器。创建两个相同的表foo
和foo_tmp
TRUNCATE foo_tmp;
INSERT INTO foo_tmp SELECT ...;
ALTER TABLE foo RENAME TO foo_tmp1;
ALTER TABLE foo_tmp RENAME TO foo;
ALTER TABLE foo_tmp1 RENAME TO foo_tmp;
由于PostgreSQL的事务性DDL功能,如果在事务中完成此操作,则重命名将在没有其他事务通知的情况下执行。您还可以将其与#3和删除/创建索引结合使用。
Pro:执行的I / O较少,如#2,并且没有锁定其他阅读器(仅在重命名部分期间执行锁定)。
Con:最复杂的。此外,您不能拥有指向该表的外键或视图,因为它们在重命名后会指向错误的表。
答案 1 :(得分:2)
当您必须删除表中的所有记录时,请使用TRUNCATE而不是DROP TABLE或DELETE。使用TRUNCATE,您仍然可以在PostgreSQL中使用触发器,并且权限更容易设置和维护。
与DROP类似,TRUNCATE也需要表锁。
答案 2 :(得分:1)
如果您正在谈论逐个手动执行INSERT
,那么DROP
/ CREATE
会更快。此外,使用CREATE TABLE AS
时,它仅复制列定义。指数和其他约束将不被复制。这将极大地加速复制过程 。但是你必须记得在完成后在新副本上重新创建这些。
SELECT INTO
也是如此。它们在功能上是相同的。他们只是有不同的名字。
无论如何。复制大表时,请始终禁用触发器,索引和约束以获得性能。
答案 3 :(得分:0)
以下是整数的答案的比较时间(请参见下面的代码):
放置索引/截断/插入/创建索引-13秒。
-- preparations
drop table if exists temp_refresh_experiment;
-- million random strings
create table temp_refresh_experiment as
select
upper(substr(md5(random()::text), 0, 25)) as some_column
FROM
generate_series(1,1000000) i;
-- create index
create index temp_refresh_experiment_ix on temp_refresh_experiment(some_column)
;
-- 1. delete/insert
delete from temp_refresh_experiment;
insert into temp_refresh_experiment(some_column)
select
upper(substr(md5(random()::text), 0, 25)) as some_column
FROM
generate_series(1,1000000) i;
-- 36 secs
-- 2. truncate/insert
truncate temp_refresh_experiment;
insert into temp_refresh_experiment(some_column)
select
upper(substr(md5(random()::text), 0, 25)) as some_column
FROM
generate_series(1,1000000) i;
-- 19 sec
-- 3. drop index/truncate/insert/create index
drop index if exists temp_refresh_experiment_ix;
truncate temp_refresh_experiment;
insert into temp_refresh_experiment(some_column)
select
upper(substr(md5(random()::text), 0, 25)) as some_column
FROM
generate_series(1,1000000) i;
create index temp_refresh_experiment_ix on temp_refresh_experiment(some_column)
;
-- 13 sec