2015-06-11 2 views
3

я встретил странное поведение оптимизатора Postgres на следующий запросе:Почему этот запрос не использует индекс?

select count(product0_.id) as col_0_0_ from Product product0_ 
where product0_.active=true 
and (product0_.aggregatorId is null 
or product0_.aggregatorId in ($1 , $2 , $3)) 

Product имеет около 54 столбцов, active является булевым, имеющим индекс ВТКЕЯ и aggregatorId является «VARCHAR (15)` и имеет индекс btree.

В этом запросе выше индекса для «aggregatorId» не используется:

Aggregate (cost=169995.75..169995.76 rows=1 width=32) (actual time=3904.726..3904.727 rows=1 loops=1) 
    -> Seq Scan on product product0_ (cost=0.00..165510.39 rows=1794146 width=32) (actual time=0.055..2407.195 rows=1851827 loops=1) 
     Filter: (active AND ((aggregatorid IS NULL) OR ((aggregatorid)::text = ANY ('{5109037,5001015,70601}'::text[])))) 
     Rows Removed by Filter: 542146 
Total runtime: 3904.925 ms 

Но если уменьшить запрос на выходе из проверки нулевой для этого столбца, индекс привыкает:

Aggregate (cost=17600.93..17600.94 rows=1 width=32) (actual time=614.933..614.935 rows=1 loops=1) 
    -> Index Scan using idx_prod_aggr on product product0_ (cost=0.43..17487.56 rows=45347 width=32) (actual time=19.284..594.509 rows=12099 loops=1) 
     Index Cond: ((aggregatorid)::text = ANY ('{5109037,5001015,70601}'::text[])) 
     Filter: active 
    Rows Removed by Filter: 49130 
Total runtime: 150.255 ms 

Насколько я знаю, индекс btree может обрабатывать нулевые проверки, поэтому я не понимаю, почему индекс не используется для полного запроса. В таблице продуктов содержится около 2,3 миллиона записей, поэтому это не очень быстро.

EDIT: Индекс стандартны:

CREATE INDEX idx_prod_aggr 
    ON product 
    USING btree 
    (aggregatorid COLLATE pg_catalog."default"); 
+1

Можете ли вы показать нам результат «объяснить анализ»? –

+0

@a_horse_with_no_name Я добавил оба объяснения результатов анализа. –

+0

Возможно ли, что слишком много строк с нулями в aggregatorId? –

ответ

1

Поскольку существует много одинаковых значений для столбца, который вы используете в предложении where (78% всех строк таблицы в соответствии с вашими числами), база данных будет заключать, что дешевле использовать полное сканирование таблицы, чем тратить дополнительное время для чтения индекса.

Правило большого пальца у большинства поставщиков баз данных заключается в том, что индекс, вероятно, не будет использоваться, если он не сможет сузить поиск до примерно 5% всех записей таблицы.

+0

Есть ли способ сказать Postgres использовать другое поведение для данного случая? Потому что здесь imho было бы быстрее использовать индекс. –

+0

@UweAllner: вы можете использовать 'set enable_seqscan = off', прежде чем запускать запрос, чтобы отключить использование seq-сканирования, - но я был бы удивлен, если бы индексный поиск для этих многих строк был бы действительно дешевле/быстрее. –

+0

@a_horse_with_no_name Да, вы правы, это займет 10 секунд после отключения seqscan ... –

1

Ваша проблема выглядела интересно, поэтому я воспроизвел свой сценарий - Postgres 9.1, таблица со строками 1M, один логический столбец, один VARCHAR столбец как индексированный, половина таблицы имеет NULL-имена.

У меня был такой же анализ анализа вывода, когда колонка varchar была не с индексом. Тем не менее, с помощью postgres index использует растровое сканирование в состоянии NULL и условие IN, а затем объединяет их с условием OR.

Затем он использует НомерСтарт сканирования на логическом условии (так как индексы разделены)

explain analyze 
select * from A where active is true and ((name is null) OR (name in ('1','2','3') )); 

См выход:

"Bitmap Heap Scan on a (cost=17.34..21.35 rows=1 width=18) (actual time=0.048..0.048 rows=0 loops=1)" 
" Recheck Cond: ((name IS NULL) OR ((name)::text = ANY ('{1,2,3}'::text[])))" 
" Filter: (active IS TRUE)" 
" -> BitmapOr (cost=17.34..17.34 rows=1 width=0) (actual time=0.047..0.047 rows=0 loops=1)" 
"  -> Bitmap Index Scan on idx_prod_aggr (cost=0.00..4.41 rows=1 width=0) (actual time=0.010..0.010 rows=0 loops=1)" 
"    Index Cond: (name IS NULL)" 
"  -> Bitmap Index Scan on idx_prod_aggr (cost=0.00..12.93 rows=1 width=0) (actual time=0.036..0.036 rows=0 loops=1)" 
"    Index Cond: ((name)::text = ANY ('{1,2,3}'::text[]))" 
"Total runtime: 0.077 ms" 

Это заставляет меня думать, что вы пропустили некоторые детали, если это так, добавьте их на ваш вопрос.

Смежные вопросы