当where子句仅包含索引的第一列时,为什么不使用索引?

时间:2019-06-06 22:00:56

标签: sql postgresql

这是select语句:

SELECT COUNT(*) FROM object_detection_label where company_id = 'SOME_COMPANY_ID'

行数: 4700万

表格列:id,company_id,job_id,flight_plan_id,media_id,顶部,左侧,底部,右侧,置信度class_id,classes_version,display_id。

主键: ID

索引: company_id,job_id,flight_plan_id,media_id

结果来自:EXPLAIN ANALYZE SELECT * FROM object_detection_label where company_id = 'SOME_COMPANY_ID';

"Bitmap Heap Scan on object_detection_label  (cost=41048.21..1042966.23 rows=614131 width=153) (actual time=62.563..216.589 rows=592653 loops=1)"
"  Recheck Cond: ((company_id)::text = 'SOME_COMPANY_ID'::text)"
"  Heap Blocks: exact=14303"
"  ->  Bitmap Index Scan on company_id_job_id_fp_id_media_id_idx  (cost=0.00..40894.67 rows=614131 width=0) (actual time=60.170..60.170 rows=592653 loops=1)"
"        Index Cond: ((company_id)::text = 'SOME_COMPANY_ID'::text)"
"Planning time: 0.061 ms"
"Execution time: 316.966 ms"

结果来自:EXPLAIN ANALYZE SELECT * FROM object_detection_label where company_id = 'SOME_COMPANY_ID' and job_id = 'SOME_JOB_ID';

"Index Scan using company_id_job_id_fp_id_media_id_idx on object_detection_label  (cost=0.69..418.71 rows=102 width=153) (actual time=0.064..6.912 rows=13206 loops=1)"
"  Index Cond: (((company_id)::text = 'CHURCH_OF_JESUS_CHRIST'::text) AND ((job_id)::text = '5cc085baa635404e54ebd46e'::text))"
"Planning time: 0.110 ms"
"Execution time: 10.114 ms"

请注意,它是在位子句的一部分使用位图热扫描,而不是索引扫描(如果我包含job_id,它将使用索引扫描)。

在仅将索引添加到company_id之后,它仍然没有使用索引扫描。为什么会这样呢?如何使用索引扫描?

1 个答案:

答案 0 :(得分:2)

位图索引扫描 是一种索引扫描。

结果集是47000000行中的600万行,它们位于14000个块中。

这意味着使用正常的索引扫描,每个块将不得不被访问几次,这效率很低。位图索引扫描按顺序提取所需的表块,并且每个块仅提取一次。 PostgreSQL估计这会更有效,这可能是正确的。

您可以通过在设置后重新运行查询来验证这一点

SET enable_bitmapscan = off;