Postgres может использовать это, но делает это немного (несколько) менее эффективно, чем индекс, указывающий where user_type = 'Standard'
.
Я создал небольшую тестовую таблицу с 4 миллионами строк, из которых 10.000 имеюттип_пользователя 'Standard'
.Другие значения были распределены случайным образом с помощью следующего сценария:
create table user_table
(
id serial primary key,
some_date date not null,
user_type text not null,
some_ts timestamp not null,
some_number integer not null,
some_data text,
some_flag boolean
);
insert into user_table (some_date, user_type, some_ts, some_number, some_data, some_flag)
select current_date,
case (random() * 4 + 1)::int
when 1 then 'PowerPartner'
when 2 then 'CSPLitePortal'
when 3 then 'CustomerSuccess'
when 4 then 'PowerCustomerSuccess'
when 5 then 'CsnOnly'
end,
clock_timestamp(),
42,
rpad(md5(random()::text), (random() * 200 + 1)::int, md5(random()::text)),
(random() + 1)::int = 1
from generate_series(1,4e6 - 10000) as t(i)
union all
select current_date,
'Standard',
clock_timestamp(),
42,
rpad(md5(random()::text), (random() * 200 + 1)::int, md5(random()::text)),
(random() + 1)::int = 1
from generate_series(1,10000) as t(i);
(я создаю таблицы, в которых больше, чем несколько столбцов, поскольку выбор планировщика также определяется размером и шириной таблиц)
Первый тест с использованием индекса с NOT IN:
create index ix_not_in on user_table(user_type)
where user_type not in ('PowerPartner', 'CSPLitePortal', 'CustomerSuccess', 'PowerCustomerSuccess', 'CsnOnly');
explain (analyze true, verbose true, buffers true)
select *
from user_table
where user_type = 'Standard'
Результат:
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on stuff.user_table (cost=139.68..14631.83 rows=11598 width=139) (actual time=1.035..2.171 rows=10000 loops=1)
Output: id, some_date, user_type, some_ts, some_number, some_data, some_flag
Recheck Cond: (user_table.user_type = 'Standard'::text)
Buffers: shared hit=262
-> Bitmap Index Scan on ix_not_in (cost=0.00..136.79 rows=11598 width=0) (actual time=1.007..1.007 rows=10000 loops=1)
Index Cond: (user_table.user_type = 'Standard'::text)
Buffers: shared hit=40
Total runtime: 2.506 ms
(Выше приведено типичное время выполнения после запускапримерно 10 раз, чтобы устранить проблемы с кэшированием)
Как вы можете видеть, планировщик использует сканирование индекса растрового изображения, которое представляет собой сканирование с потерями, которое требует дополнительного шага для фильтрации ложных срабатываний.
При использовании следующего индекса:
create index ix_standard on user_table(id)
where user_type = 'Standard';
Это приводит к следующему плану:
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------
Index Scan using ix_standard on stuff.user_table (cost=0.29..443.16 rows=10267 width=139) (actual time=0.011..1.498 rows=10000 loops=1)
Output: id, some_date, user_type, some_ts, some_number, some_data, some_flag
Buffers: shared hit=313
Total runtime: 1.815 ms
Вывод:
Ваш индекс используется, ноиндекс только для интересующего вас типа немного более эффективен.
Время выполнения не сильно отличается.Я выполнял каждое объяснение примерно 10 раз, и среднее значение для индекса ix_standard
было немного ниже 2 мс, а среднее значение для индекса ix_not_in
было немного выше 2 мс, так что разница в производительности не была реальной.
Но в целом индексное сканирование будет масштабироваться лучше при увеличении размеров таблицы, чем это делает растровое сканирование индекса.Это в основном связано с «перепроверкой условия» - особенно если недостаточно work_mem для хранения растрового изображения в памяти (для больших таблиц).