Postgresql大表更新速度减慢

Postgresql大表更新速度减慢,postgresql,postgresql-9.4,Postgresql,Postgresql 9.4,我在一个大表(例如8GB)上运行更新。这是表中3个字段的简单更新。我在postgresql 9.1下运行它没有问题,它需要40-60分钟,但它工作正常。我在9.4数据库中运行了相同的查询(新创建的,未升级),它很好地启动了更新,但随后速度变慢了。它只使用约2%的CPU,如果IO为4-5MB/s,并且它位于那里,则该级别为。没有锁,没有其他查询或连接,只有服务器上的这一次SQL更新 下面是SQL语句。“查找”表有12条记录。查找只能返回一行,它将离散比例(SMALLINT,-32768..+327

我在一个大表(例如8GB)上运行更新。这是表中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文件以执行查询,并且它以>40 MB/s的速度运行,而且我只有一个磁盘(这是一个带有ISCSI介质的虚拟机)。所有其他磁盘操作都不受影响,有足够的IO带宽。与此同时,PostgreSQL只是坐在那里做很少的事情,运行非常缓慢

我有两台虚拟化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();
“邮局主管已命令此服务器进程回滚当前事务并退出,因为另一个服务器进程异常退出,可能损坏共享内存”“-这是否表示PostgreSQL中存在错误

编辑
我测试了9.1、9.3和9.4。9.1和9.3都没有经历减速。9.4大额交易持续放缓。我注意到,当一个事务启动时,htop监视器指示高CPU,进程状态为“R”(正在运行)。然后它逐渐变为低CPU使用率和状态“D”-磁盘(见屏幕截图)。我最大的问题是为什么9.4不同于9.1和9.3?我有十几台服务器,这种效果在所有的硬盘上都可以观察到。

我怀疑很多磁盘搜索—5MB/s对于普通(旋转)硬盘上的非常随机的IO来说几乎是合适的

当您不断地替换基本上所有的行时,我会尝试将
dest
table fillfactor设置为大约45%(
alter table dest set(fillfactor=45);
),然后使用test\u pkey进行
集群测试。这将允许在同一磁盘扇区中放置更新的行版本

另外,使用src_pkey使用
集群src这样两个表在磁盘上具有相同物理顺序的数据也会有所帮助

还记得
真空工作台dest在每次如此大的更新之后,旧的行版本可以在后续更新中再次使用


您的旧服务器可能会在多次更新过程中自然更新。在新服务器上,它是100%打包的,因此更新的行必须放在末尾。

如果只有很少的目标行实际更新,您可以通过使用
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
        )
        ;

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

通过禁用透明的大型页面,问题得以解决:

echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
以下是一些我发现有助于重新整理问题的资源:
*
*

*

您最近是否从9.1升级到9.4?导入后是否运行了
vacuum analyze
?这是全新安装,不是升级。我并行运行2台独立的Linux服务器。数据库是从CSV文件导入的,在书籍加载完成后,表会显式清空。这在9.1上顺利运行了多年。感觉9.4进程悄然失败并暂停/挂起。是否启用了复制或归档?另外,update语句如何?查找表中有多少行满足该条件?另外:0)表描述,包括键和索引1)调优常量,2)查询计划。3个想法:1-您是否尝试在两台服务器上运行解释计划以查看是否有任何差异?2-您是否检查过快速数据库中是否有一些索引不在慢速数据库中?3-您是否同时运行两个虚拟机?可能第一个虚拟机已消耗了所有主机内存,而另一个虚拟机必须使用更多的交换空间。是的,以前的版本默认情况下不使用大型页面。顺便说一句,你有没有注意到运行9.4时系统时间占总时间的百分比很高?它通常表示这类问题。
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
        )
        ;
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag