3

我在一个大表(例如 8 GB)上运行更新。这是对表中 3 个字段的简单更新。我在 postgresql 9.1 下运行它没有问题,它需要 40-60 分钟,但它有效。我在 9.4 数据库中运行相同的查询(新创建,未升级),它开始更新正常但随后变慢。它只使用约 2% 的 CPU,如果 IO 为 4-5MB/s 并且它就坐在那里,那么它的水平。没有锁,没有其他查询或连接,只有服务器上的这个单一更新 SQL。

SQL如下。“查找”表有 12 条记录。查找只能返回一行,它将离散比例(SMALLINT,-32768 .. +32767)分解为非重叠区域。“src”和“dest”表大约有 6000 万条记录。

UPDATE dest SET
    field1 = src.field1,
    field2 = src.field2,
    field3_id = (SELECT lookup.id FROM lookup WHERE src.value BETWEEN lookup.min AND lookup.max)
FROM src
WHERE dest.id = src.id;

我以为我的磁盘速度变慢了,但我可以并行复制 1 GB 文件来执行查询,它以 >40MB/s 的速度运行,而且我只有一个磁盘(它是一个带有 ISCSI 介质的 VM)。所有其他磁盘操作均不受影响,IO 带宽充足。与此同时,PostgreSQL 只是坐在那里做的很少,运行得很慢。

我有 2 台虚拟化 linux 服务器,一台运行 postgresql 9.1,另一台运行 9.4。两台服务器都具有几乎相同的 postgresql 配置。

有没有其他人有类似的经历?我的想法不多了。帮助。

编辑 查询“运行”了 20 个小时,我不得不终止连接并重新启动服务器。令人惊讶的是,它并没有通过查询终止连接:

SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE pid <> pg_backend_pid() AND datname = current_database();

并服务器产生了以下日志:

2015-05-21 12:41:53.412 EDT FATAL:  terminating connection due to administrator command
2015-05-21 12:41:53.438 EDT FATAL:  terminating connection due to administrator command
2015-05-21 12:41:53.438 EDT STATEMENT:  UPDATE <... this is 60,000,000 record table update statement>

服务器重启也需要很长时间,产生以下日志:

2015-05-21 12:43:36.730 EDT LOG:  received fast shutdown request
2015-05-21 12:43:36.730 EDT LOG:  aborting any active transactions
2015-05-21 12:43:36.730 EDT FATAL:  terminating connection due to administrator command
2015-05-21 12:43:36.734 EDT FATAL:  terminating connection due to administrator command
2015-05-21 12:43:36.747 EDT LOG:  autovacuum launcher shutting down
2015-05-21 12:44:36.801 EDT LOG:  received immediate shutdown request
2015-05-21 12:44:36.815 EDT WARNING:  terminating connection because of crash of another server process
2015-05-21 12:44:36.815 EDT DETAIL:  The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.

“邮局主管已命令此服务器进程回滚当前事务并退出,因为另一个服务器进程异常退出并且可能损坏了共享内存” - 这是否表明 PostgreSQL 中存在错误?

编辑 我测试了 9.1、9.3 和 9.4。9.1 和 9.3 都没有减速。9.4 一直在大笔交易上放慢速度。我注意到,当事务启动时,htop 监视器指示 CPU 高且进程状态为“R”(正在运行)。然后它逐渐变为低 CPU 使用率和状态“D” - 磁盘(见截图磁盘等待)。我最大的问题是为什么 9.4 与 9.1 和 9.3 不同?我有十几台服务器,并且全面观察到这种效果。

4

3 回答 3

4

感谢大家的帮助。无论我多么试图强调相同配置9.4和以前版本之间的性能差异,似乎都没有人注意到这一点。

通过禁用透明大页面解决了该问题:

echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

以下是我发现有助于研究问题的一些资源:
* https://dba.stackexchange.com/questions/32890/postgresql-pg-stat-activity-shows-commit/34169#34169
* https://lwn.net /Articles/591723/
* https://blogs.oracle.com/linux/entry/performance_issues_with_transparent_huge

于 2015-06-02T01:44:03.637 回答
0

我怀疑很多磁盘搜索 - 5MB/s 对于普通(旋转)硬盘驱动器上的非常随机的 IO 来说几乎是正确的。

当您不断替换基本上所有行时,我会尝试将dest表填充因子设置为大约 45% ( alter table dest set (fillfactor=45);),然后cluster test using test_pkey;. 这将允许将更新的行版本放置在同一磁盘扇区中。

此外,使用cluster src using src_pkey;这样两个表在磁盘上的物理顺序相同的数据也会有所帮助。

还要记住vacuum table dest;在每次更新后都要大,这样旧的行版本可以在后续更新中再次使用。

您的旧服务器可能在多次更新期间自然地演变了它的填充因子。在新服务器上,它是 100% 打包的,因此必须将更新的行放在最后。

于 2015-05-21T22:04:15.900 回答
0

如果实际上只更新了少数目标行,则可以避免使用DISTICNT FROM. 这可以防止大量无用的磁盘流量。

UPDATE dest SET
    field1 = src.field1,
    field2 = src.field2,
    field3_id = lu.id
FROM src
JOIN lookup lu ON src.value BETWEEN lu.min AND lu.max
WHERE dest.id = src.id
        -- avoid unnecessary row versions to be generated
AND     (dest.field1 IS DISTINCT FROM src.field1
        OR dest.field1 IS DISTINCT FROM src.field1
        OR dest.field3_id IS DISTINCT FROM lu.id
        )
        ;
于 2015-05-22T10:19:58.133 回答