#postgresql #query-performance #database-indexes
#postgresql #запрос-производительность #база данных-индексы
Вопрос:
Я хочу выбрать между использованием 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. Я думаю, что причиной этого обычно было бы «индекс не может преобразовать обратно значение в нижнем регистре, поэтому ему нужно заглянуть в таблицу», но SELECT lower (a) также не будет использовать только индекс.
Ответ №1:
Ваш тест вводит в заблуждение. Здесь есть две проблемы:
-
Вы не запустились
ANALYZE
после создания индексаlowertextind
.Без этого PostgreSQL не знает, как
lower(a)
распределяется, и, вероятно, приведет к неправильной оценке затрат. -
Используя
SELECT *
, вы непреднамеренно разрешили использовать сканирование только индекса для первого запроса, но не для второго. Это потому, что первый индекс содержит все столбцы таблицы, а второй — нет.Поскольку второй индекс не содержит
a
, значение должно быть извлечено из таблицы, что приводит к дополнительной работе.Вы могли бы использовать
SELECT count(*) FROM ...
для более справедливого теста.