【发布时间】:2018-02-02 19:17:13
【问题描述】:
我正在尝试对一个包含 6 个表的大型数据库应用 125 种不同的更新,每个表的记录范围从 10 万到 3 亿条记录。
每次更新都包含要插入到原始 6 个表中的新数据,但是更新还包含将成为原始表中已存在记录的下一个版本的数据。如果是这种情况,那么我需要使用更新负载编号更新一个字段。更新数据和原始数据包含一个唯一 id,它是一个 20 个字符的 varchar,在原始表和更新表上都有一个标准 BTree 索引。
原始数据的一个例子是这样的
unique_id, version, version_date, change_dates,"tlzb1000001554000601";7;"2003-12-22";"{1995-12-04,1995-12-14,2002-06-21,2002-06-25,2003-12-16}"
更新记录是
unique_id, version, version_date, change_dates,"tlzb1000001554000601";8;"2004-08-10";"{1995-12-04,1995-12-14,2002-06-21,2002-06-25,2003-12-16,2004-07-27}"
由于我需要跟踪影响记录的更新编号,我已在原始数据表中添加了一个 update_number,如果有匹配的 unique_id 记录,我希望更新该更新编号。
因此,对于每次更新,我都将数据加载到一组 6 个表中,这些表与我的原始数据的架构相匹配,然后应用更新,以便任何正在更新的记录我将更新的整数字段设置为更新的数字我正在处理。
UPDATE original_table
SET load_number = ${update_number}
WHERE unique_id IN (SELECT unique_id FROM update_table)
这效果不佳,每次更新通常需要 10 多个小时。经过一番研究,我发现了这个advice,因此将我的查询更改为使用 CTE 和“FROM”
WITH new AS (
SELECT unique_id
FROM update_table
)
UPDATE original_table o
SET load_number = ${update_number}
FROM new n
WHERE o.unique_id=n.unique_id
使用上述查询,我在一周内 24/7 运行了 32 次更新。我试图通过暂时关闭表的 auto_vacuum 来加快速度。
我还尝试将数据删除加载到临时表中,然后将它们与更新的字段一起插入。
WITH new AS (
SELECT unique_id FROM update_table
), tmp AS (
DELETE FROM original_table b
USING new n
WHERE b.unique_id=n.unique_id
RETURNING *)
INSERT INTO old_data SELECT * FROM tmp
但这似乎需要 4 倍的时间。
所以我现在已经用尽了我能想到的所有变化,所以我在尝试一些我可以尝试的替代方案。
我想到但不确定如何实现的一个可能选项是将所有更新数据加载到 6 个更新表中,并将 load_number 字段设置为更新编号。完成所有 125 次更新后,我将使用这些表来修改原始表。但不确定我将如何以正确的顺序更新记录并将 load_number 设置为正确的。
希望有人有解决方案,在此先感谢
额外信息:- 我在具有 20 个内核和 128Gb RAM 的 Windows 64 位服务器上有一个 PostgreSQL 9.6 数据库。我已经根据 wiki 调整建议调整了数据库。
【问题讨论】:
-
找出哪些查询花费的时间最多(使用
pg_stat_statements)并开始处理这些。
标签: sql postgresql postgresql-performance