postgresql 查询无法完成
A postgresql query won't finish
在 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 个小时都没有成功。
然后它占据 cpu.
的 100%
此查询唯一需要的锁是 "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 这种格式的查询:
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 日志不显示长 运行ning 查询的任何条目,因为它们永远不会完成,因此永远不会被记录。
知道什么可能导致这种行为以及如何防止它发生吗?
没有分析的解释计划:
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))
VACUUM ANALYZE VERBOSE;
刷新统计数据将帮助数据库选择最佳计划 - 而不是嵌套循环,我相信这需要 100% CPU
这个问题可能是因为(据我了解):
- Postgres 有 运行 个可用的 t运行saction id(当所有 20 亿个可用的 t运行saction ID 都被使用时,t运行操作 ID 从一个开始重新开始,这会导致环绕问题,从而导致严重的数据丢失或数据库关闭)
- 数据库过于分段,即 DELETE 或 UPDATE(它被 Postgres 转换为 INSERT + DELETE)命令将元组标记为已删除但不实际删除它。
如果你有像 GCloud 这样的云服务器,你可以在 数据库标志 上设置一些变量来自动调用 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/
在 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 个小时都没有成功。 然后它占据 cpu.
的 100%此查询唯一需要的锁是 "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 这种格式的查询:
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 日志不显示长 运行ning 查询的任何条目,因为它们永远不会完成,因此永远不会被记录。
知道什么可能导致这种行为以及如何防止它发生吗?
没有分析的解释计划:
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))
VACUUM ANALYZE VERBOSE;
刷新统计数据将帮助数据库选择最佳计划 - 而不是嵌套循环,我相信这需要 100% CPU
这个问题可能是因为(据我了解):
- Postgres 有 运行 个可用的 t运行saction id(当所有 20 亿个可用的 t运行saction ID 都被使用时,t运行操作 ID 从一个开始重新开始,这会导致环绕问题,从而导致严重的数据丢失或数据库关闭)
- 数据库过于分段,即 DELETE 或 UPDATE(它被 Postgres 转换为 INSERT + DELETE)命令将元组标记为已删除但不实际删除它。
如果你有像 GCloud 这样的云服务器,你可以在 数据库标志 上设置一些变量来自动调用 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/