Yan*_*ang 47 postgresql performance bulk update
在 Ubuntu 12.04 上使用 PG 9.1。
目前,我们在数据库上运行大量 UPDATE 语句最多需要 24 小时,它们的形式如下:
UPDATE table
SET field1 = constant1, field2 = constant2, ...
WHERE id = constid
Run Code Online (Sandbox Code Playgroud)
(我们只是覆盖由 ID 标识的对象的字段。)这些值来自外部数据源(尚未在数据库中的表中)。
每个表都有几个索引,没有外键约束。直到最后都没有提交。
导入pg_dump整个数据库的一个需要 2 小时。这似乎是我们应该合理定位的基线。
除了生成以某种方式重建数据集以供 PostgreSQL 重新导入的自定义程序之外,我们是否可以做些什么来使批量 UPDATE 性能更接近导入的性能?(这是一个我们认为日志结构合并树处理得很好的领域,但我们想知道是否可以在 PostgreSQL 中做任何事情。)
一些想法:
基本上有很多事情要尝试,但我们不确定什么是最有效的,或者我们是否忽略了其他事情。我们将在接下来的几天里进行实验,但我们想我们也会在这里问。
我确实在表上有并发负载,但它是只读的。
Erw*_*ter 58
由于 Q 中缺少信息,我将假设:
COPY输出一样,每行都有一个唯一的 id以匹配目标表。COPY选项来处理格式。我建议您采用第三个项目符号链接中概述的类似方法。进行了重大优化。
要创建临时表,有一种更简单快捷的方法:
CREATE TEMP TABLE tmp_tbl AS SELECT * FROM tbl LIMIT 0;
Run Code Online (Sandbox Code Playgroud)
UPDATE来自数据库内部临时表的单个 big将比来自数据库外部的单个更新快几个数量级。
在PostgreSQL 的 MVCC 模型中,一种UPDATE创建新行版本并将旧版本标记为已删除的方法。这大约INSERT与 a 和 aDELETE组合一样昂贵。另外,它会给你留下很多死元组。由于无论如何您都在更新整个表,因此只需创建一个新表并删除旧表总体上会更快。
如果您有足够的可用 RAM,请设置temp_buffers(仅针对此会话!)足够高以将临时表保存在 RAM 中 - 在您执行任何其他操作之前。
要估计需要多少 RAM,请使用小样本运行测试并使用db 对象大小函数:
SELECT pg_size_pretty(pg_relation_size('tmp_tbl')); -- complete size of table
SELECT pg_column_size(t) FROM tmp_tbl t LIMIT 10; -- size of sample rows
Run Code Online (Sandbox Code Playgroud)
SET temp_buffers = '1GB'; -- example value
CREATE TEMP TABLE tmp_tbl AS SELECT * FROM tbl LIMIT 0;
COPY tmp_tbl FROM '/absolute/path/to/file';
CREATE TABLE tbl_new AS
SELECT t.col1, t.col2, u.field1, u.field2
FROM tbl t
JOIN tmp_tbl u USING (id);
-- Create indexes like in original table
ALTER TABLE tbl_new ADD PRIMARY KEY ...;
CREATE INDEX ... ON tbl_new (...);
CREATE INDEX ... ON tbl_new (...);
-- exclusive lock on tbl for a very brief time window!
DROP TABLE tbl;
ALTER TABLE tbl_new RENAME TO tbl;
DROP TABLE tmp_tbl; -- will also be dropped at end of session automatically
Run Code Online (Sandbox Code Playgroud)
表上的并发操作(我在开始时的假设中排除了)将等待,一旦表在接近结束时被锁定并在事务提交后立即失败,因为表名立即解析为其 OID,但是新表具有不同的 OID。表保持一致,但并发操作可能会出现异常并且必须重复。此相关答案中的详细信息:
如果您(必须)走这UPDATE条路线,请删除更新期间不需要的任何索引,然后重新创建它。一次性创建索引比为每一行更新索引要便宜得多。这也可以允许热更新。
我UPDATE在关于 SO 的这个密切相关的答案中概述了一个类似的过程。
| 归档时间: |
|
| 查看次数: |
68881 次 |
| 最近记录: |