【问题标题】:A postgresql query won't finishpostgresql 查询不会完成
【发布时间】:2015-08-01 12:06:33
【问题描述】:

在 postgresl 9.0 上,我们有一个 sql 查询:

SELECT count(*) FROM lane 
WHERE not exists 
    (SELECT 1 FROM id_map 
    WHERE id_map.new_id=lane.lane_id  
    and id_map.column_name='lane_id' 
    and id_map.table_name='lane') 
and lane.lane_id is not null;

这通常需要大约 1.5 秒才能完成。 这是解释计划:http://explain.depesz.com/s/axNN

虽然此查询有时会挂起并且不会完成。它甚至可能运行 11 个小时而没有成功。 然后它会占用 100% 的 cpu。

此查询使用的唯一锁是“AccessShareLock”,它们都被授予。

SELECT a.datname,
         c.relname,
         l.transactionid,
         l.mode,
         l.granted,
         a.usename,
         a.current_query, 
         a.query_start,
         age(now(), a.query_start) AS "age", 
         a.procpid 
    FROM  pg_stat_activity a
     JOIN pg_locks         l ON l.pid = a.procpid
     JOIN pg_class         c ON c.oid = l.relation
    ORDER BY a.query_start;

查询作为 java 进程的一部分运行,该进程使用连接池连接到数据库并按顺序执行这种格式的类似选择查询:

SELECT count(*) FROM {}  WHERE not exists (SELECT 1 FROM id_map WHERE id_map.new_id={}.{} and id_map.column_name='{}' and id_map.table_name='{}') and {}.{} is not null

没有更新或删除与此过程并行发生,因此我认为吸尘不是这里的问题。 在运行整个过程之前(因此在运行 6 个此类查询之前)对所有表进行了分析。

postgres 日志不显示长时间运行的查询的任何条目,因为它们永远不会完成,因此永远不会被记录。

知道什么可能导致这种行为以及如何防止它发生吗?

没有分析的解释计划:

Aggregate  (cost=874337.91..874337.92 rows=1 width=0)
  ->  Nested Loop Anti Join  (cost=0.00..870424.70 rows=1565283 width=0)
        Join Filter: (id_map.new_id = lane.lane_id)
        ->  Seq Scan on lane  (cost=0.00..30281.84 rows=1565284 width=8)
              Filter: (lane_id IS NOT NULL)
        ->  Materialize  (cost=0.00..816663.60 rows=1 width=8)
              ->  Seq Scan on id_map  (cost=0.00..816663.60 rows=1 width=8)
                    Filter: (((column_name)::text = 'lane_id'::text) AND ((table_name)::text = 'lane'::text))

【问题讨论】:

  • 我对 java 有同样的问题。它不是 postgres 版本 - 它是 java 没有终止连接...... postgres 或 java 的 100% CPU?.. pg_stat_activity 中有什么?..
  • 100% 来自 postgres。 pg_stat_activity 显示一个永无止境的 sql 查询
  • 当 CPU 达到 100% 时,你能检查一下计划吗?.. 它可能是嵌套循环而不是哈希连接 - 这意味着你给缓存的 RAM 太少了......另一种方法是“统计数据有多新鲜”但是如果执行计划在达到 100% CPU 时不同,两者都值得研究
  • 我不熟悉检查已经运行的 sql 查询的执行计划的任何方法。我已经在我的帖子中附上了一般的 sql 查询的执行计划。您知道任何访问正在运行的查询的真实计划的方法吗?
  • 你不能。除非有一些花哨的扩展......我要求做的解释选择......(跳过分析)以查看预期的计划

标签: sql postgresql postgresql-9.0


【解决方案1】:
VACUUM ANALYZE VERBOSE;

刷新统计信息将帮助 db 选择最佳计划 - 而不是嵌套循环,我相信这会占用 100% 的 CPU

【讨论】:

  • 我设法验证这确实是问题的根本原因。嵌套循环创建了 150 万次 id_map 表的序列扫描,这需要几天时间才能完成。在运行查询之前对两个表进行真空分析时,查询会在 2 秒内完成。
【解决方案2】:

这个问题可能是因为(据我了解):

  • Postgres 已用完可用事务 ID 的数量(当所有 20 亿个可用事务 ID 都已使用时,事务 ID 从一个重新开始,这会导致环绕问题,从而导致严重的数据丢失或数据库关闭)
  • 数据库过于分段,即 DELETE 或 UPDATE(它由 Postgres 转换为 INSERT + DELETE)命令将元组标记为已删除,但并未物理删除它。

如果你有任何像 GCloud 这样的云服务器,你可以在 Database flags 上设置一些变量,以使 VACUUM 被自动调用并清理标记为已删除且仍在您的数据库中的元组,并 ANALYZE 收集有关执行计划中使用的频繁更新表的最新统计信息。示例:

autovacuum: on
autovacuum_analyze_scale_factor: 0.05
autovacuum_analyze_threshold: 10
autovacuum_naptime: 15
autovacuum_vacuum_cost_delay: 10
autovacuum_vacuum_cost_limit: 1000
autovacuum_vacuum_scale_factor: 0.1
autovacuum_vacuum_threshold: 25
log_autovacuum_min_duration: 0
track_counts: on

来源:

https://www.postgresql.org/docs/9.5/runtime-config-autovacuum.html https://www.techonthenet.com/postgresql/autovacuum.php https://aws.amazon.com/premiumsupport/knowledge-center/transaction-id-wraparound-effects/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-23
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多