在首次填充資料庫時,可能需要插入大量資料。本節提供了一些關於如何使此過程儘可能高效的建議。
當使用多個 INSERT
時,關閉自動提交,最後只執行一次提交。(在純 SQL 中,這意味著在開始時發出 BEGIN
,在結束時發出 COMMIT
。某些客戶端庫可能會在您不知情的情況下進行此操作,在這種情況下,您需要確保庫在您想要執行時執行此操作。)如果您允許每次插入都單獨提交,PostgreSQL 將為新增的每一行執行大量工作。一次事務中所有插入的另一個好處是,如果某一行插入失敗,那麼到那時為止插入的所有行的插入都將被回滾,這樣您就不會陷入部分載入的資料中。
COPY
#使用 COPY
命令一次性載入所有行,而不是使用一系列 INSERT
命令。COPY
命令針對載入大量行進行了最佳化;它不像 INSERT
那樣靈活,但對於大量資料載入的開銷要小得多。由於 COPY
是一個單獨的命令,因此如果您使用此方法填充表,則無需停用自動提交。
如果您不能使用 COPY
,那麼使用 PREPARE
建立一個準備好的 INSERT
語句,然後根據需要多次使用 EXECUTE
,可能會有所幫助。這可以避免重複解析和規劃 INSERT
的一些開銷。不同的介面以不同的方式提供此功能;請參閱介面文件中的“準備好的語句”。
請注意,使用 COPY
載入大量行幾乎總是比使用 INSERT
快,即使使用了 PREPARE
並且將多個插入分批到一個事務中。
COPY
在與之前的 CREATE TABLE
或 TRUNCATE
命令在同一事務中使用時速度最快。在這種情況下,不需要寫入 WAL,因為如果發生錯誤,包含新載入資料的檔案將被刪除。但是,只有當 wal_level 設定為 minimal
時,此考慮才適用,因為否則所有命令都必須寫入 WAL。
如果您正在載入一個新建立的表,最快的方法是建立表,使用 COPY
大量載入表資料,然後建立表所需的任何索引。在已有資料上建立索引比在載入每一行時進行增量更新要快。
如果您正在向現有表新增大量資料,那麼刪除索引,載入表,然後重新建立索引可能會有所收益。當然,在索引缺失期間,其他使用者的資料庫效能可能會受到影響。另外,在刪除唯一索引之前應該三思,因為在索引缺失期間,唯一約束提供的錯誤檢查將丟失。
就像索引一樣,外部索引鍵約束可以比逐行檢查更有效地“批次”檢查。因此,刪除外部索引鍵約束,載入資料,然後重新建立約束可能會有用。同樣,在資料載入速度和約束缺失期間的錯誤檢查丟失之間存在權衡。
此外,當您將資料載入到具有現有外部索引鍵約束的表中時,每一行新行都需要在伺服器的待處理觸發器事件列表中有一個條目(因為檢查行外部索引鍵約束的是觸發器的觸發)。載入數千萬行可能會導致觸發器事件佇列溢位可用記憶體,從而導致無法忍受的交換或命令的直接失敗。因此,在載入大量資料時,刪除並重新應用外部索引鍵可能是必要的,而不僅僅是可取的。如果暫時刪除約束是不可接受的,那麼唯一的其他解決辦法可能是將載入操作分成更小的事務。
maintenance_work_mem
#在載入大量資料時,暫時增加 maintenance_work_mem 配置變數可以提高效能。這將有助於加快 CREATE INDEX
命令和 ALTER TABLE ADD FOREIGN KEY
命令的速度。它對 COPY
本身作用不大,所以這個建議只在您使用以上一種或兩種技術時有用。
max_wal_size
#暫時增加 max_wal_size 配置變數也可以使大資料載入更快。這是因為將大量資料載入到 PostgreSQL 中會導致檢查點比正常檢查點頻率(由 checkpoint_timeout
配置變數指定)更頻繁地發生。每當發生檢查點時,所有髒頁都必須重新整理到磁碟。透過在批次資料載入期間暫時增加 max_wal_size
,可以減少所需的檢查點數量。
當將大量資料載入到使用 WAL 歸檔或流複製的安裝中時,在載入完成後獲取新的基本備份可能比處理大量增量 WAL 資料更快。為了防止在載入過程中進行增量 WAL 日誌記錄,請透過將 wal_level 設定為 minimal
,將 archive_mode 設定為 off
,並將 max_wal_senders 設定為零來停用歸檔和流複製。但請注意,更改這些設定需要伺服器重啟,並且會使之前獲取的任何基本備份無法用於歸檔恢復和備用伺服器,這可能會導致資料丟失。
除了避免歸檔程式或 WAL 傳送器處理 WAL 資料的時間外,這樣做實際上可以使某些命令更快,因為如果 wal_level
是 minimal
並且當前子事務(或頂層事務)建立或截斷了它們更改的表或索引,它們根本不需要寫入 WAL。(它們可以透過在末尾執行 fsync
來更便宜地保證崩潰安全性,而不是寫入 WAL。)
ANALYZE
#每當您顯著更改了表內資料的分佈時,強烈建議執行 ANALYZE
。這包括將大量資料批次載入到表中。執行 ANALYZE
(或 VACUUM ANALYZE
)可確保規劃器具有關於表的最新統計資訊。如果沒有統計資訊或統計資訊過時,規劃器在查詢規劃期間可能會做出錯誤的決定,導致具有不準確或不存在統計資訊的任何表的效能下降。請注意,如果啟用了 autovacuum 守護程式,它可能會自動執行 ANALYZE
;有關更多資訊,請參閱 第 24.1.3 節 和 第 24.1.6 節。
pg_dump 生成的轉儲指令碼會自動應用上述幾點,但並非全部。為了儘快恢復 pg_dump 的轉儲,您需要手動執行一些額外的操作。(請注意,這些要點適用於恢復轉儲時,而不是建立轉儲時。無論是使用 psql 載入文字轉儲還是使用 pg_restore 從 pg_dump 歸檔檔案中載入,都要考慮相同的要點。)
預設情況下,pg_dump 使用 COPY
,並且在生成完整的模式和資料轉儲時,它會小心地在建立索引和外部索引鍵之前載入資料。因此,在這種情況下,有幾點建議是自動處理的。您需要做的是:
為 maintenance_work_mem
和 max_wal_size
設定適當的值(即大於正常值)。
如果使用 WAL 歸檔或流複製,請考慮在恢復期間停用它們。為此,在載入轉儲之前,將 archive_mode
設定為 off
,將 wal_level
設定為 minimal
,並將 max_wal_senders
設定為零。之後,將它們恢復到正確的值並進行新的基本備份。
嘗試 pg_dump 和 pg_restore 的並行轉儲和恢復模式,並找到最佳的併發作業數量。-j
選項進行的並行轉儲和恢復應該比序列模式提供更高的效能。
考慮是否應該將整個轉儲作為單個事務進行恢復。為此,將 -1
或 --single-transaction
命令列選項傳遞給 psql 或 pg_restore。使用此模式時,即使是最小的錯誤也將回滾整個恢復過程,可能浪費數小時的處理時間。根據資料的相互關聯程度,這可能比手動清理更可取,也可能不。如果您使用單個事務並且關閉了 WAL 歸檔,COPY
命令的執行速度會更快。
如果資料庫伺服器中有多個 CPU 可用,請考慮使用 pg_restore 的 --jobs
選項。這允許並行載入資料和建立索引。
完成後執行 ANALYZE
。
僅資料轉儲仍將使用 COPY
,但它不會刪除或重新建立索引,也不會正常觸及外部索引鍵。[14] 因此,在載入僅資料轉儲時,如果您想使用這些技術,則需要自己刪除並重新建立索引和外部索引鍵。在載入資料時增加 max_wal_size
仍然有用,但不要費心增加 maintenance_work_mem
;您應該在之後手動重新建立索引和外部索引鍵時進行。並且不要忘記在完成時執行 ANALYZE
;有關更多資訊,請參閱 第 24.1.3 節 和 第 24.1.6 節。
如果您在文件中發現任何不正確、與您對特定功能的體驗不符或需要進一步澄清的內容,請使用 此表格 報告文件問題。