【问题标题】:Postgresql large table update slows downPostgresql大表更新变慢
【发布时间】:2015-08-03 08:54:30
【问题描述】:

我在一个大表(例如 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.

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

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

【问题讨论】:

  • 您最近是否从 9.1 升级到 9.4?导入后你运行vacuum analyze 了吗?
  • 这是一个全新的安装,而不是升级。我正在并行运行 2 个独立的 Linux 服务器。数据库是从 CSV 文件导入的,并且在图书加载完成后,表会被显式清除。这在 9.1 上运行良好多年。感觉就像 9.4 进程悄悄地失败并停止/挂起。
  • 是否启用了复制或归档?还有,更新语句怎么样?
  • 查找表有多少行满足条件?另外:0) 表描述,包括键和索引 1) 调整常量,2) 查询计划。
  • 3 个想法: 1 - 您是否尝试在两台服务器上运行解释计划以查看是否有任何区别? 2 - 您是否检查过快速数据库中是否有一些索引不在慢速数据库中? 3-您是否同时运行两个虚拟机?也许第一个虚拟机已经消耗了所有的主机内存,而另一个虚拟机必须使用更多的交换空间。

标签: postgresql postgresql-9.4


【解决方案1】:

我怀疑很多磁盘搜索 - 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% 打包的,因此必须将更新的行放在最后。

【讨论】:

    【解决方案2】:

    如果实际上只更新了少数目标行,则可以使用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
            )
            ;
    

    【讨论】:

      【解决方案3】:

      感谢大家的帮助。无论我多么强调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

      【讨论】:

      • 是的,以前的版本默认不使用大页面。顺便说一句,您在运行 9.4 时是否注意到高 %sy(系统时间在顶部)?它通常表示此类问题。
      猜你喜欢
      • 1970-01-01
      • 2019-08-20
      • 2021-07-03
      • 1970-01-01
      • 2011-04-07
      • 1970-01-01
      • 2011-03-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多