在PostgreSQL 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))