2011-08-11 31 views
4

我必须将一个表中的值复制到另一个表中(相同的表格方案)。什么是更好的(性能):PostgreSQL中的DROP和CREATE与DELETE和INSERT

  • 降表1和创造为SELECT * FROM表2
  • 删除从表1中的所有行,并从表2中插入的所有行

更新: 我做了一个在几乎3k行的桌子上进行小型测试。 删除并创建约60ms vs删除并插入 - 约30ms。

+0

我的直觉告诉我最快的方法是截断和插入,因为删除扫描每一行并单独删除它们,而截断只是简单地清空没有可能条件的表。 –

+1

3k rows ....认真?....而你正在谈论性能?...不成熟的优化任何人?当我读到你最初的帖子时,我以为你在谈论数百万行。 3k行是* nothing *。对于3k行,你可能甚至不需要数据库;) – exhuma

+3

那么取决于他需要多久执行一次以及并发事务需要多长时间才能访问它,不是吗? :) – intgr

回答

13

我看到四种有用的方法来替换表中的内容。他们中没有一个“显然是正确的”,但这取决于您的要求。

  1. (在一个单一的交易)DELETE FROM foo; INSERT INTO foo SELECT ...

    临:最佳并发性:不会锁定访问表中的其他交易,因为它充分利用的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 ...,重新创建所有索引。

    专业版:大表最快,因为创建索引CREATE INDEX比增量更新更快。

    缺点:同#2

  4. 的switcheroo。创建两个相同的表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,并且不锁定其他读取器(仅在重命名部分进行锁定)。

    骗局:最复杂的。

+1

我必须重新命名/删除我的索引#4和#3组合后。主键索引自动重命名,其他则不是。从视图中删除和重建〜800.000行的总时间从90秒到20秒左右。谢谢你的提示。 –

1

如果您正在谈论手动执行INSERT s,则会一个接一个,然后DROP/CREATE会快得多。另外,当使用CREATE TABLE AS时,它会只有复制列定义。指数和其他限制不会被复制。这将极大地加速复制过程。但是一旦完成,您必须记住在新副本上重新创建这些内容。

SELECT INTO也是如此。它们在功能上是相同的。他们只是有不同的名字。

无论如何。复制大型表格时,请始终禁用触发器,索引和约束以获得性能。

2

当您必须摆脱表中的所有记录时,请使用TRUNCATE而不是DROP TABLE或DELETE。使用TRUNCATE,您仍然可以在PostgreSQL中使用触发器,并且更容易设置和维护权限。

和DROP一样,TRUNCATE也需要一个表锁。