2011-08-11 32 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也需要一個表鎖。