在PostgreSQL中DROP和CREATE vs DELETE和INSERT

时间:2011-08-11 07:49:42

标签: performance postgresql

我要将值从一个表复制到另一个表(相同的表格方案)。什么是更好的(性能):

  • 删除table1并从table2
  • 创建select *
  • 删除table1中的所有行并插入table2
  • 中的所有行

更新: 我在桌子上进行了一次小测试,排了近3k行。 删除和创建提供大约60毫秒与删除和插入 - 约30毫秒。

4 个答案:

答案 0 :(得分:14)

我看到了四种有用的方法来替换表的内容。它们都不是“明显正确”,但这取决于您的要求。

  1. (在单笔交易中)DELETE FROM foo; INSERT INTO foo SELECT ...

    Pro:最佳并发:不会锁定访问该表的其他事务,因为它利用了Postgres的MVCC。

    Con:如果单独测量插入速度,可能是最慢的。导致autovacuum清理死行,从而产生更高的I / O负载。

  2. TRUNCATE foo; INSERT INTO foo SELECT ...

    专业版:小表最快。写入I / O少于#1

    Con:排除所有其他读者 - 从表中读取的其他交易必须等待。

  3. TRUNCATE foo,DROP表上的所有索引INSERT INTO foo SELECT ...,重新创建所有索引。

    Pro:对于大型表来说最快,因为使用CREATE INDEX创建索引比以递增方式更新索引要快。

    Con:与#2相同

  4. 切换器。创建两个相同的表foofoo_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)

以下是整数的答案的比较时间(请参见下面的代码):

  1. 删除/插入-36秒。
  2. 截断/插入-19秒。
  3. 放置索引/截断/插入/创建索引-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