Почему Postgres по-прежнему выполняет сканирование кучи Bitmap, когда используется покрывающий индекс? - PullRequest
2 голосов
/ 10 июля 2020

Таблица выглядит примерно так:

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'

Как я и ожидал, план запроса использует сканирование индекса Bitmap (предположительно, чтобы найти столбец 'entity') и сканирование кучи Bitmap (я предполагаю, чтобы получить столбец 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)

Почему?

1 Ответ

3 голосов
/ 10 июля 2020

PostgreSQL реализует управление версиями строк, используя концепцию, называемую видимость . Каждый запрос знает, какую версию строки он видит.

Теперь, когда информация о видимости хранится в строке таблицы, но не в записи индекса, поэтому эту таблицу нужно посещать только для проверки того, является ли строка видимым или нет.

Из-за этого каждое сканирование индекса битовой карты требует сканирования кучи битовой карты.

Чтобы преодолеть неудачное свойство, PostgreSQL представил карту видимости, структура данных, которая хранится для каждого блока размером 8 КБ в таблице, если все строки в этом блоке видны всем. В этом случае поиск строки таблицы можно пропустить. Это возможно только для обычного сканирования индекса, но не для сканирования индекса растрового изображения.

Эта карта видимости поддерживается VACUUM. Так что запустите VACUUM в таблице, тогда вы можете получить сканирование только индекса в таблице.

Если этого недостаточно, вы можете попробовать CLUSTER, чтобы переписать таблицу в порядке индекса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...