【问题标题】:Postgres won't use index depending on specific value of id in where clausePostgres 不会根据 where 子句中 id 的特定值使用索引
【发布时间】:2017-01-17 20:26:25
【问题描述】:

我已经修补/阅读了一段时间,但找不到任何可以在这里工作的优化...我已经在连接中索引了相关的 id,我尝试了手动清理,我还尝试了集群一个索引,这样查询优化器可能不会认为扫描整个表更有效,因为有一些分散的行(尽管我对查询计划不太了解)。

我正在尝试获取单个 id 的加入结果(用于调试目的)。我发现查询某些单个 id 大约需要 2 分钟,而大多数(99%?)会在 1 秒内返回。这里有一些explain analyzes(为了保密,我用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 行,添加“LIMIT 100”也可以使查询立即返回。我调查了速度是否与查询返回的数据量有关,我没有看到任何明显的趋势。我不禁觉得 Postgres 关于哪种方法会更快是完全错误的(100 倍?)。我在这里有什么选择?

【问题讨论】:

  • SELECT e.customer_id, l.* FROM abc.encounter e JOIN abc.log l ON e.encounter_id = l.encounter_id WHERE e.customer_id = '1655563'你能试试这个查询,看看它是否更快?
  • @HaleemurAli,这种格式需要的时间一样长。我还尝试了“WHERE id in (subselect)”样式和普通的 in 子句。
  • 您是否获得了与WHERE l.customer_id = '1655563' 类似的性能?
  • @HaleemurAli,customer_id 不是此“日志”表的列。出于我们的目的,该表只有遇到_id。
  • 对不起我的错字,我的意思是在上面的评论中写 l.encounter_id = '1655563'。那应该是一样的结果

标签: postgresql indexing database-optimization query-planner


【解决方案1】:

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 偏向于嵌套循环连接。

【讨论】:

  • 这解决了我的问题,谢谢!你知道为什么 Postgres 有这么糟糕的估计吗?这只是不时发生的事情,还是必须在配置等方面犯错误才能导致混淆?如果有帮助,这是一个 Amazon RDS 实例,我没有玩弄任何参数。
  • default_statistics_target 的默认值 100 试图达到一个中间地带:高到足以获得不错的统计数据,低到不会在统计数据收集期间造成过度的工作量。通常默认值可以正常工作,但有时需要调整。
猜你喜欢
  • 2012-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-02
  • 2020-01-02
  • 2021-07-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多