我正在尝试对包含6个表的大型数据库应用125个不同的更新,每个表中包含100k条记录到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
使用上述查询,我设法在一周内全天候运行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设置为正确的记录。
希望有人有解决方案,提前谢谢
额外信息: - 我在Windows 64位服务器上有一个PostgreSQL 9.6数据库,有20个内核和128Gb的RAM。我根据wiki调优建议调整了数据库。