【问题标题】:Postgres does a expensive index scanPostgres 进行昂贵的索引扫描
【发布时间】:2022-01-16 02:44:50
【问题描述】:

我有一张表,其中包含 3 个月的约 450 万条数据。我已经对“accessedAt”列进行了索引,该列存储了纪元中的时间并具有 BIGINT 数据类型,当我运行查询时,postgres 对 700K 行进行了位图索引扫描。在(〜48.2秒)。但是当我删除索引时,它在(~4s)内对 700K 行进行了 seq 扫描。

[QUERY] explain analyze select id from access_histories where "accessedAt" >= 1631903400 and "accessedAt" <= 1633112999; 即从 2021 年 9 月 17 日至 2021 年 10 月 1 日。

Bitmap Heap Scan on access_histories  (cost=14655.35..144416.85 rows=715992 width=8) (actual time=238.837..21154.597 rows=715535 loops=1)
   Recheck Cond: (("accessedAt" >= 1631903400) AND ("accessedAt" <= 1633112999))
   Rows Removed by Index Recheck: 1716759
   Heap Blocks: exact=48015 lossy=33133
   Buffers: shared hit=3 read=82972 written=8
   I/O Timings: read=19860.378 write=4.389
   ->  Bitmap Index Scan on "access_histories_accessedAt_idx"  (cost=0.00..14476.35 rows=715992 width=0) (actual time=229.267..229.272 rows=715535 loops=1)
         Index Cond: (("accessedAt" >= 1631903400) AND ("accessedAt" <= 1633112999))
         Buffers: shared hit=3 read=1824
         I/O Timings: read=62.423
 Planning:
   Buffers: shared hit=20 read=1
   I/O Timings: read=0.012
 Planning Time: 1.168 ms
 Execution Time: 21198.731 ms

删除索引后。

 Seq Scan on access_histories  (cost=0.00..155405.02 rows=715992 width=8) (actual time=0.035..10278.345 rows=715535 loops=1)
   Filter: (("accessedAt" >= 1631903400) AND ("accessedAt" <= 1633112999))
   Rows Removed by Filter: 4234466
   Buffers: shared hit=23814 read=57341
   I/O Timings: read=2083.283
 Planning:
   Buffers: shared hit=76 read=17
   I/O Timings: read=7.851
 Planning Time: 8.286 ms
 Execution Time: 10316.716 ms
(10 rows)

所以我的问题是为什么 postgres 选择进行索引扫描,尽管顺序扫描成本更低。

p.s I know that postgres will go for seq scan if it has to query 5-10% of total data.

【问题讨论】:

  • 您的查询选择了多少行(平均)?
  • 试试索引access_histories (accessedAt, id)
  • 如果您查看您的 4 个计划(预编辑和当前),我们会发现相同计划的重复执行在它们之间的时间上有很大差异。鉴于一个计划的时间安排如此不连贯,我认为尝试解释计划之间的差异没有多大意义。谁知道这种差异是否真实存在,而不仅仅是随机变化?
  • 平均会因所选时间范围而异。 @The Impaler
  • @jjanes 所以我的问题是为什么 postgres 选择进行索引扫描,尽管顺序扫描成本更低。

标签: sql postgresql


【解决方案1】:

有几件事可以在这方面协同工作:

  1. work_mem 太低,位图堆扫描无法像 PostgreSQL 一样有效 (Heap Blocks: lossy=33133)

    如果work_mem 太小而无法包含每个表行有一个位的位图,PostgreSQL 会在某个时候将位图降级为每 8kB 块一个位。对于这样的“有损”块,如果满足条件,则必须重新检查块的所有行,这意味着额外的工作。

  2. 在第二次查询期间,缓存了更多数据(使用EXPLAIN (ANALYZE, BUFFERS) 跟踪)

【讨论】:

  • 我已根据您对缓冲区的输入更新了问题。其次,我想了解更多关于work_mem的信息,请您指出一些文章或文档。谢谢。
  • 我已经添加了解释。
猜你喜欢
  • 1970-01-01
  • 2019-12-08
  • 2021-06-23
  • 1970-01-01
  • 1970-01-01
  • 2011-03-27
  • 2021-10-09
  • 2015-04-22
  • 1970-01-01
相关资源
最近更新 更多