Postgres 不会根据 where 子句中 id 的特定值使用索引
Postgres won't use index depending on specific value of id in where clause
我 tinkering/reading 已经有一段时间了,但找不到任何在这里工作的优化...我已经在连接中索引了相关的 ID,我尝试了手动清理,然后我还尝试在索引上进行聚类,这样查询优化器可能不会认为扫描整个 table 更有效,因为一些分散的行(尽管我对查询计划不太了解)。
我正在尝试获取单个 ID 的连接结果(用于调试目的)。我发现查询某些单个 ID 需要大约 2 分钟,而大多数(99%?)return 不到 1 秒。这里有一些explain analyze
s(为了保密我用sed改了一些名字):
main=> explain analyze SELECT e.customer_id, l.*
FROM abc.encounter e
JOIN abc.log l
ON e.encounter_id = l.encounter_id
AND e.customer_id = '1655563';
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------
Hash Join (cost=2751.69..2566740.95 rows=13262 width=75) (actual time=122038.725..226694.004 rows=249 loops=1)
Hash Cond: (l.encounter_id = e.encounter_id)
-> Seq Scan on log l (cost=0.00..2190730.92 rows=99500192 width=66) (actual time=0.005..120825.675 rows=99500192 loops=1)
-> Hash (cost=2742.81..2742.81 rows=710 width=18) (actual time=0.309..0.309 rows=89 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 13kB
-> Bitmap Heap Scan on encounter e (cost=17.93..2742.81 rows=710 width=18) (actual time=0.037..0.197 rows=89 loops=1)
Recheck Cond: (customer_id = '1655563'::text)
Heap Blocks: exact=46
-> Bitmap Index Scan on idx_abc_encounter_customer_id (cost=0.00..17.76 rows=710 width=0) (actual time=0.025..0.025 rows=89 loops=1)
Index Cond: (customer_id = '1655563'::text)
Planning time: 0.358 ms
Execution time: 226694.311 ms
(12 rows)
main=> explain analyze SELECT e.customer_id, l.*
FROM abc.encounter e
JOIN abc.log l
ON e.encounter_id = l.encounter_id
AND e.customer_id = '121652491';
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------
Nested Loop (cost=36.67..53168.06 rows=168 width=75) (actual time=0.090..0.422 rows=11 loops=1)
-> Index Scan using idx_abc_encounter_customer_id on encounter e (cost=0.43..40.53 rows=9 width=18) (actual time=0.017..0.047 rows=17 loops=1)
Index Cond: (customer_id = '121652491'::text)
-> Bitmap Heap Scan on log l (cost=36.24..5888.00 rows=1506 width=66) (actual time=0.016..0.017 rows=1 loops=17)
Recheck Cond: (encounter_id = e.encounter_id)
Heap Blocks: exact=6
-> Bitmap Index Scan on idx_abc_log_encounter_id (cost=0.00..35.86 rows=1506 width=0) (actual time=0.013..0.013 rows=1 loops=17)
Index Cond: (encounter_id = e.encounter_id)
Planning time: 0.361 ms
Execution time: 0.478 ms
(10 rows)
我还要补充一点,对于一个很长的运行查询,即使2分钟后只有250行被return编辑,添加"LIMIT 100"可以使查询return 立即。我调查了速度是否与查询的数据量 return 有关,但我没有看到任何明显的趋势。我不禁觉得 Postgres 完全错误(100 倍?)关于它的哪些方法会更快。我在这里有什么选择?
PostgreSQL 对 encounter
的行数估计差了将近 10 倍。我的第一个尝试是改进它。
为此,您可以更改列的统计目标:
ALTER TABLE abc.encounter ALTER customer_id SET STATISTICS 1000;
随后的 ANALYZE
将为该列收集更好的统计信息。如果 1000 不够,请尝试 10000。有了更好的行数估计,您就有更好的机会获得最佳计划。
如果与顺序扫描相比,嵌套循环连接的重复索引扫描成本仍然被高估,您可以将参数 random_page_cost
从默认值 4 降低到更接近 seq_page_cost
(默认为 1)。这将使 PostgreSQL 偏向于嵌套循环连接。
我 tinkering/reading 已经有一段时间了,但找不到任何在这里工作的优化...我已经在连接中索引了相关的 ID,我尝试了手动清理,然后我还尝试在索引上进行聚类,这样查询优化器可能不会认为扫描整个 table 更有效,因为一些分散的行(尽管我对查询计划不太了解)。
我正在尝试获取单个 ID 的连接结果(用于调试目的)。我发现查询某些单个 ID 需要大约 2 分钟,而大多数(99%?)return 不到 1 秒。这里有一些explain analyze
s(为了保密我用sed改了一些名字):
main=> explain analyze SELECT e.customer_id, l.*
FROM abc.encounter e
JOIN abc.log l
ON e.encounter_id = l.encounter_id
AND e.customer_id = '1655563';
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------
Hash Join (cost=2751.69..2566740.95 rows=13262 width=75) (actual time=122038.725..226694.004 rows=249 loops=1)
Hash Cond: (l.encounter_id = e.encounter_id)
-> Seq Scan on log l (cost=0.00..2190730.92 rows=99500192 width=66) (actual time=0.005..120825.675 rows=99500192 loops=1)
-> Hash (cost=2742.81..2742.81 rows=710 width=18) (actual time=0.309..0.309 rows=89 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 13kB
-> Bitmap Heap Scan on encounter e (cost=17.93..2742.81 rows=710 width=18) (actual time=0.037..0.197 rows=89 loops=1)
Recheck Cond: (customer_id = '1655563'::text)
Heap Blocks: exact=46
-> Bitmap Index Scan on idx_abc_encounter_customer_id (cost=0.00..17.76 rows=710 width=0) (actual time=0.025..0.025 rows=89 loops=1)
Index Cond: (customer_id = '1655563'::text)
Planning time: 0.358 ms
Execution time: 226694.311 ms
(12 rows)
main=> explain analyze SELECT e.customer_id, l.*
FROM abc.encounter e
JOIN abc.log l
ON e.encounter_id = l.encounter_id
AND e.customer_id = '121652491';
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------
Nested Loop (cost=36.67..53168.06 rows=168 width=75) (actual time=0.090..0.422 rows=11 loops=1)
-> Index Scan using idx_abc_encounter_customer_id on encounter e (cost=0.43..40.53 rows=9 width=18) (actual time=0.017..0.047 rows=17 loops=1)
Index Cond: (customer_id = '121652491'::text)
-> Bitmap Heap Scan on log l (cost=36.24..5888.00 rows=1506 width=66) (actual time=0.016..0.017 rows=1 loops=17)
Recheck Cond: (encounter_id = e.encounter_id)
Heap Blocks: exact=6
-> Bitmap Index Scan on idx_abc_log_encounter_id (cost=0.00..35.86 rows=1506 width=0) (actual time=0.013..0.013 rows=1 loops=17)
Index Cond: (encounter_id = e.encounter_id)
Planning time: 0.361 ms
Execution time: 0.478 ms
(10 rows)
我还要补充一点,对于一个很长的运行查询,即使2分钟后只有250行被return编辑,添加"LIMIT 100"可以使查询return 立即。我调查了速度是否与查询的数据量 return 有关,但我没有看到任何明显的趋势。我不禁觉得 Postgres 完全错误(100 倍?)关于它的哪些方法会更快。我在这里有什么选择?
PostgreSQL 对 encounter
的行数估计差了将近 10 倍。我的第一个尝试是改进它。
为此,您可以更改列的统计目标:
ALTER TABLE abc.encounter ALTER customer_id SET STATISTICS 1000;
随后的 ANALYZE
将为该列收集更好的统计信息。如果 1000 不够,请尝试 10000。有了更好的行数估计,您就有更好的机会获得最佳计划。
如果与顺序扫描相比,嵌套循环连接的重复索引扫描成本仍然被高估,您可以将参数 random_page_cost
从默认值 4 降低到更接近 seq_page_cost
(默认为 1)。这将使 PostgreSQL 偏向于嵌套循环连接。