gpt4 book ai didi

postgresql - 为什么在使用覆盖索引时 Postgres 仍然进行位图堆扫描?

转载 作者:行者123 更新时间:2023-12-04 12:37:39 24 4
gpt4 key购买 nike

该表看起来像这样:

CREATE TABLE "audit_log" (
"id" int4 NOT NULL DEFAULT nextval('audit_log_id_seq'::regclass),
"entity" varchar(50) COLLATE "public"."ci",
"updated" timestamp(6) NOT NULL,
"transaction_id" uuid,
CONSTRAINT "PK_audit_log" PRIMARY KEY ("id")
);
它包含数百万行。
我尝试在这样的一列上添加索引:
CREATE INDEX "testing" ON "audit_log" USING btree (
"entity" COLLATE "public"."ci" "pg_catalog"."text_ops" ASC NULLS LAST
);
然后对索引列和主键运行以下查询:
EXPLAIN ANALYZE SELECT entity, id FROM audit_log WHERE entity = 'abcd'
正如我所料,查询计划同时使用位图索引扫描(大概是查找“实体”列)和位图堆扫描(我假设是检索“id”列):
Gather  (cost=2640.10..260915.23 rows=87166 width=122) (actual time=2.828..3.764 rows=0 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Parallel Bitmap Heap Scan on audit_log (cost=1640.10..251198.63 rows=36319 width=122) (actual time=0.061..0.062 rows=0 loops=3)
Recheck Cond: ((entity)::text = '1234'::text)
-> Bitmap Index Scan on testing (cost=0.00..1618.31 rows=87166 width=0) (actual time=0.036..0.036 rows=0 loops=1)
Index Cond: ((entity)::text = '1234'::text)
接下来,我向索引添加了一个 INCLUDE 列,以使其覆盖上述查询:
DROP INDEX testing

CREATE INDEX testing ON audit_log USING btree (
"entity" COLLATE "public"."ci" "pg_catalog"."text_ops" ASC NULLS LAST
)
INCLUDE
(
"id"
)
然后我重新运行我的查询,但它仍然执行位图堆扫描:
Gather  (cost=2964.10..261239.23 rows=87166 width=122) (actual time=2.711..3.570 rows=0 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Parallel Bitmap Heap Scan on audit_log (cost=1964.10..251522.63 rows=36319 width=122) (actual time=0.062..0.062 rows=0 loops=3)
Recheck Cond: ((entity)::text = '1234'::text)
-> Bitmap Index Scan on testing (cost=0.00..1942.31 rows=87166 width=0) (actual time=0.029..0.029 rows=0 loops=1)
Index Cond: ((entity)::text = '1234'::text)
这是为什么?

最佳答案

PostgreSQL 使用称为可见性的概念实现行版本控制。每个查询都知道它可以看到行的哪个版本。
现在可见性信息存储在表行中,但不在索引条目中,因此必须访问该表以测试该行是否可见。
因此,每个位图索引扫描都需要位图堆扫描。
为了克服这个不幸的特性,PostgreSQL 引入了可见性映射,这是一种数据结构,如果每个人都可以看到该块中的所有行,则该数据结构将为表的每个 8kB 块存储。如果是这种情况,可以跳过查找表行。这仅适用于常规索引扫描,而不适用于位图索引扫描。
该可见性 map 由 VACUUM 维护.所以运行VACUUM在表上,那么您可能会在表上获得仅索引扫描。
如果仅此还不够,您可以尝试 CLUSTER按索引顺序重写表。

关于postgresql - 为什么在使用覆盖索引时 Postgres 仍然进行位图堆扫描?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62834678/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com