繁体   English   中英

PostgreSQL:查询限制使其不使用索引

[英]PostgreSQL: Limit in query makes it not use index

我有一个带有 BRIN 索引的大表,如果我用限制查询它会忽略索引和 go 进行序列扫描,没有它使用索引(我尝试了几次,结果相同)

explain (analyze,verbose,buffers,timing,costs) 
select *
from testj.cdc_s5_gpps_ind
where id_transformace = 1293
limit 100

Limit  (cost=0.00..349.26 rows=100 width=207) (actual time=28927.179..28927.214 rows=100 loops=1)
  Output: id, date_key_trainjr...
  Buffers: shared hit=225 read=1680241
  ->  Seq Scan on testj.cdc_s5_gpps_ind  (cost=0.00..3894204.10 rows=1114998 width=207) (actual time=28927.175..28927.202 rows=100 loops=1)
        Output: id, date_key_trainjr...
        Filter: (cdc_s5_gpps_ind.id_transformace = 1293)
        Rows Removed by Filter: 59204140
        Buffers: shared hit=225 read=1680241
Planning Time: 0.149 ms
Execution Time: 28927.255 ms

explain (analyze,verbose,buffers,timing,costs) 
select *
from testj.cdc_s5_gpps_ind
where id_transformace = 1293

Bitmap Heap Scan on testj.cdc_s5_gpps_ind  (cost=324.36..979783.34 rows=1114998 width=207) (actual time=110.103..467.008 rows=1073725 loops=1)
  Output: id, date_key_trainjr...
  Recheck Cond: (cdc_s5_gpps_ind.id_transformace = 1293)
  Rows Removed by Index Recheck: 11663
  Heap Blocks: lossy=32000
  Buffers: shared hit=32056
  ->  Bitmap Index Scan on gpps_brin_index  (cost=0.00..45.61 rows=1120373 width=0) (actual time=2.326..2.326 rows=320000 loops=1)
        Index Cond: (cdc_s5_gpps_ind.id_transformace = 1293)
        Buffers: shared hit=56
Planning Time: 1.343 ms
JIT:
  Functions: 2
  Options: Inlining true, Optimization true, Expressions true, Deforming true
  Timing: Generation 0.540 ms, Inlining 32.246 ms, Optimization 44.423 ms, Emission 22.524 ms, Total 99.732 ms
Execution Time: 537.627 ms

这种行为有原因吗?

x86_64-pc-linux-gnu 上的 PostgreSQL 12.3,由 gcc (GCC) 8.3.1 20191121 (Red Hat 8.3.1-5) 编译,64 位

这有一个非常简单(也不是很好)的原因。 规划器假设 id_transformace = 1293 的行均匀分布在整个表中,因此它将能够通过 seq 扫描非常快速地收集其中的 100 个,然后提前停止。 但是这个假设是非常错误的,需要go 通过表的一大块找到100 个符合条件的行。

这个假设不是基于在表上收集的任何统计信息,因此增加统计信息目标将无济于事。 扩展统计信息也无济于事,因为它只提供列之间的统计信息,而不是列和物理排序之间的统计信息。

纯粹在股票服务器端没有很好的干净方法来解决这个问题。 一种解决方法是在运行查询之前set enable_seqscan=off ,然后重置后记。 另一种方法是将ORDER BY random()添加到您的查询中,这样计划者就知道它不能提前停止。 或者扩展pg_hint_plan可能会有所帮助,我从未使用过它。

您可能会通过调整您的一些 *_cost 参数来更改计划,但这可能会使其他事情变得更糟。 看到使用 enable_seqscan=off 运行的 LIMITed 查询的 EXPLAIN (ANALYZE, BUFFERS) 的 output 可以告知该决定。

由于该列似乎稀疏/倾斜,您可以尝试增加统计信息大小:


ALTER TABLE testj.cdc_s5_gpps_ind
  ALTER COLUMN id_transformace SET STATISTICS  1000;

ANALYZE testj.cdc_s5_gpps_ind;

Postgres-11 及更高版本还具有扩展的统计信息,允许识别和利用多列相关性。 您必须对表中数据的实际结构有所了解才能有效地使用它们。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM