Индекс цитирования PostgreSQL против более низкой производительности индекса выражений - PullRequest
2 голосов
/ 11 апреля 2019

Я хочу выбрать между использованием столбца citext с индексом или использованием столбца text с индексом lower().

Я выполнил несколько тестов. К моему удивлению, поиск с индексом на lower() вызывает сканирование индекса, но в случае citext я получаю сканирование только индекса. Я ожидал, что индекс на lower() также вызовет сканирование только индекса.

Кроме того, общая стоимость с индексом citext составляет 4,44, но с индексом lower() общая стоимость составляет 8,44.

Итак, первое, что приходит мне в голову, это то, что индекс столбца citext лучше, чем индекс выражения для столбца text.

CREATE TABLE test_citext(a citext NOT NULL);

INSERT INTO test_citext
   SELECT cast(x as text)
   FROM generate_series(1, 1000000) AS x;

VACUUM (FREEZE, ANALYZE) test_citext;

create index citextind on test_citext(a);

Select * from test_citext where a = 'test';
--Index Only Scan.Total cost 4.44

CREATE TABLE test_textlowerindex(a text NOT NULL);

INSERT INTO test_textlowerindex
   SELECT cast(x as text)
   FROM generate_series(1, 1000000) AS x;

VACUUM (FREEZE, ANALYZE) test_textlowerindex;

create index lowertextind on test_textlowerindex(lower(a));

Select * from test_textlowerindex where lower(a) = 'test';
--Index Scan.Total cost 8.44

Я прав?

Мистер Лоренц Олби, спасибо за ваш ответ. Я изменил мой вышеописанный сценарий, как вы сказали. Результат:

CREATE TABLE test_citext(a citext NOT NULL);

INSERT INTO test_citext
   SELECT cast(x as text)
   FROM generate_series(1, 1000000) AS x;

create index citextind on test_citext(a);

VACUUM (FREEZE, ANALYZE) test_citext;

Select count(*) from test_citext where a = 'test';
--Index Only Scan 4.44 + 4.46

CREATE TABLE test_textlowerindex(a text NOT NULL);

INSERT INTO test_textlowerindex
   SELECT cast(x as text)
   FROM generate_series(1, 1000000) AS x;

create index lowertextind on test_textlowerindex(lower(a));

VACUUM (FREEZE, ANALYZE) test_textlowerindex;

Select count(*) from test_textlowerindex where lower(a) = 'test';
--Index Scan 8.44 + 8.46


Но ничего не изменилось. Даже если я запускаю анализ после создания индекса и использования count (*) в select. Сканирование индекса все еще продолжается с индексом lower ().

1 Ответ

2 голосов
/ 11 апреля 2019

Ваш тест вводит в заблуждение. Здесь есть две проблемы:

  1. Вы не запустили ANALYZE после создания индекса lowertextind.

    Без этого PostgreSQL не знает, как распределяется lower(a), и, вероятно, даст неверную оценку стоимости.

  2. Используя SELECT *, вы случайно допустили сканирование только индекса 10101 * для первого запроса, но не для второго. Это связано с тем, что первый индекс содержит все столбцы таблицы, а второй - нет.

    Поскольку второй индекс не содержит a, значение должно быть извлечено из таблицы, что требует дополнительной работы.

    Вы можете использовать SELECT count(*) FROM ... для более точного теста.

...