![](/img/trans.png)
[英]What is the most efficient way update multiple rows in a database and log it?
[英]Most efficient way of updating ~100 million rows in Postgresql database?
我有一個帶有單個表的數據庫。 該表需要每隔幾周更新一次。 我們需要將第三方數據引入其中,它將包含 100-1.2 億行。 所以流程基本上是:
檢測和執行更新的最佳方式是什么? 一些選項是:
你建議什么是最好的選擇,或者如果有不同的選擇?
Postgres 有一個有助於提高批量加載性能的指南。 根據您的描述,除了批量UPDATE
和DELETE
之外,您還需要執行批量INSERT
。 以下是提高效率的大致分步指南:
ALTER SYSTEM SET max_wal_size = <size>;
您還可以完全禁用 WAL。
ALTER SYSTEM SET wal_level = 'minimal';
ALTER SYSTEM SET archive_mode = 'off';
ALTER SYSTEM SET max_wal_senders = 0;
請注意,這些更改需要重新啟動數據庫才能生效。
您希望所有工作都在一個事務中完成,以防出現任何問題。 跨多個連接並行運行 COPY 通常不會提高性能,因為磁盤通常是限制因素。
SET LOCAL maintenance_work_mem = <size>
...
如果您在 Postgres 中對數據進行任何額外的特殊處理,您可能需要設置其他配置參數( work_mem
通常在那里最重要,尤其是在使用 Postgis 擴展時。)請參閱 本指南以了解最重要的性能配置變量。
CREATE
一個沒有約束的TEMPORARY
表。CREATE TEMPORARY TABLE changes(
id bigint,
data text,
) ON COMMIT DROP; --ensures this table will be dropped at end of transaction
COPY FROM
批量插入changes
使用COPY FROM
命令將原始數據批量插入到臨時表中。
COPY changes(id,data) FROM ..
DROP
關系在target
表上, DROP
所有外鍵約束、索引和觸發器(如果可能)。 不要丟棄您的 PRIMARY KEY,因為您會希望它用於INSERT
。
target
表向target
表添加一列以確定更改表中是否存在行:
ALTER TABLE target ADD COLUMN seen boolean;
changes
表到target
表: 通過將ON CONFLICT
子句添加到標准INSERT
語句來執行 UPSERT。 這避免了執行兩個單獨操作的需要。
INSERT INTO target(id,data,seen)
SELECT
id,
data,
true
FROM
changes
ON CONFLICT (id) DO UPDATE SET data = EXCLUDED.data, seen = true;
DELETE
不在changes
表中的行DELETE FROM target WHERE not seen is true;
DROP
跟蹤列和臨時changes
表DROP TABLE changes;
ALTER TABLE target DROP COLUMN seen;
重新添加所有已刪除的約束、觸發器和索引以提高批量 upsert 性能。
批量更新/刪除已完成,應在事務之外執行以下命令。
target
表上運行VACUUM ANALYZE
。這將允許查詢規划器對表進行適當的推斷並回收死元組占用的空間。
SET maintenance_work_mem = <size>
VACUUM ANALYZE target;
SET maintenance_work_mem = <original size>
ALTER SYSTEM SET max_wal_size = <size>;
...
您可能需要再次重新啟動數據庫才能使這些設置生效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.