在 postgres 中查询计划在运行时更改
Query plan changes at runtime in postgres
我有两个简单的 tables:
Profile (20M entries)
----------------------------
pId | fail
123 | 0
234 | 2
345 | 0
Work (50M entries)
-----------------
pId
123
234
123
345
123
345
我只想在 Profile
中将 fail
标记为 1
table 对于 Work
中超过阈值 pId
的条目table。 Profile
table 中的 pId
已编入索引,我不想触及 fail
不是 0
.
的行
我现在使用的查询是:
UPDATE Profile
SET fail = 1
WHERE pId IN
(
SELECT pId
FROM Work
GROUP BY pId
HAVING COUNT(*) > 2
)
AND Profile.fail = 0;
在 pgAdmin 中,我得到如下解释计划:
"Update on Profile a (cost=1134492.79..1559750.23 rows=5180 width=1014)"
" -> Hash Join (cost=1134492.79..1559750.23 rows=5180 width=1014)"
" Hash Cond: (a.pId = b.pId)"
" -> Seq Scan on Profile a (cost=0.00..425216.00 rows=15462 width=976)"
" Filter: (fail = 0)"
" -> Hash (cost=1134491.95..1134491.95 rows=67 width=32)"
" -> Subquery Scan on b (cost=1134488.78..1134491.95 rows=67 width=32)"
" -> HashAggregate (cost=1134488.78..1134491.28 rows=67 width=4)"
" Group Key: Work.pId"
" Filter: (count(*) > 5)"
" -> Seq Scan on Work (cost=0.00..894341.52 rows=48029452 width=4)"
运行 需要几分钟。
现在,当这两个 table 在 运行 时使用相同的数据创建时,查询计划更改为:
"Update on Profile (cost=1250747.42..1251317.47 rows=67 width=386)"
" -> Nested Loop (cost=1250747.42..1251317.47 rows=67 width=386)"
" -> Subquery Scan on "ANY_subquery" (cost=1250746.98..1250750.15 rows=67 width=32)"
" -> HashAggregate (cost=1250746.98..1250749.48 rows=67 width=4)"
" Group Key: Work.pId"
" Filter: (count(*) > 5)"
" -> Seq Scan on Work (cost=0.00..985990.32 rows=52951332 width=4)"
" -> Index Scan using Profile_idx on Profile (cost=0.44..8.46 rows=1 width=348)"
" Index Cond: (pId = "ANY_subquery".pId)"
" Filter: (fail = 0)"
运行 需要一个小时。我什至尝试过从子查询切换到连接,但它仍然产生相同的结果。任何帮助将不胜感激。
你的问题的关键可能是:
Now when these two tables are created at runtime with the same data, the query plan changes to [the worse]
PostgreSQL 自动收集 table 统计数据,但自动分析需要一段时间才能启动。
在批量数据修改和自动分析完成之间 运行 的所有查询都可能有错误的执行计划。
在大量数据修改结束时 table 显式 运行 ANALYZE
是个好主意。
我有两个简单的 tables:
Profile (20M entries)
----------------------------
pId | fail
123 | 0
234 | 2
345 | 0
Work (50M entries)
-----------------
pId
123
234
123
345
123
345
我只想在 Profile
中将 fail
标记为 1
table 对于 Work
中超过阈值 pId
的条目table。 Profile
table 中的 pId
已编入索引,我不想触及 fail
不是 0
.
我现在使用的查询是:
UPDATE Profile
SET fail = 1
WHERE pId IN
(
SELECT pId
FROM Work
GROUP BY pId
HAVING COUNT(*) > 2
)
AND Profile.fail = 0;
在 pgAdmin 中,我得到如下解释计划:
"Update on Profile a (cost=1134492.79..1559750.23 rows=5180 width=1014)"
" -> Hash Join (cost=1134492.79..1559750.23 rows=5180 width=1014)"
" Hash Cond: (a.pId = b.pId)"
" -> Seq Scan on Profile a (cost=0.00..425216.00 rows=15462 width=976)"
" Filter: (fail = 0)"
" -> Hash (cost=1134491.95..1134491.95 rows=67 width=32)"
" -> Subquery Scan on b (cost=1134488.78..1134491.95 rows=67 width=32)"
" -> HashAggregate (cost=1134488.78..1134491.28 rows=67 width=4)"
" Group Key: Work.pId"
" Filter: (count(*) > 5)"
" -> Seq Scan on Work (cost=0.00..894341.52 rows=48029452 width=4)"
运行 需要几分钟。
现在,当这两个 table 在 运行 时使用相同的数据创建时,查询计划更改为:
"Update on Profile (cost=1250747.42..1251317.47 rows=67 width=386)"
" -> Nested Loop (cost=1250747.42..1251317.47 rows=67 width=386)"
" -> Subquery Scan on "ANY_subquery" (cost=1250746.98..1250750.15 rows=67 width=32)"
" -> HashAggregate (cost=1250746.98..1250749.48 rows=67 width=4)"
" Group Key: Work.pId"
" Filter: (count(*) > 5)"
" -> Seq Scan on Work (cost=0.00..985990.32 rows=52951332 width=4)"
" -> Index Scan using Profile_idx on Profile (cost=0.44..8.46 rows=1 width=348)"
" Index Cond: (pId = "ANY_subquery".pId)"
" Filter: (fail = 0)"
运行 需要一个小时。我什至尝试过从子查询切换到连接,但它仍然产生相同的结果。任何帮助将不胜感激。
你的问题的关键可能是:
Now when these two tables are created at runtime with the same data, the query plan changes to [the worse]
PostgreSQL 自动收集 table 统计数据,但自动分析需要一段时间才能启动。
在批量数据修改和自动分析完成之间 运行 的所有查询都可能有错误的执行计划。
在大量数据修改结束时 table 显式 运行 ANALYZE
是个好主意。