Postgres не использует индекс для запроса диапазона в многораздельной таблице

Я обнаружил, что Postgres не использует индекс для запроса диапазона в многораздельной таблице.

Столбец даты родительской таблицы и ее разделов индексируется с помощью btree.

Такой запрос:

select * from parent_table where date >= '2015-07-01';

не использует индексы.

EXPLAIN результат:

Append  (cost=0.00..106557.52 rows=3263963 width=128)
->  Seq Scan on parent_table  (cost=0.00..0.00 rows=1 width=640)
    Filter: (date >= '2015-07-01'::date)
->  Seq Scan on z_partition_2015_07  (cost=0.00..106546.02 rows=3263922 width=128)
    Filter: (date >= '2015-07-01'::date)
->  Seq Scan on z_partition_2015_08  (cost=0.00..11.50 rows=40 width=640)
    Filter: (date >= '2015-07-01'::date)

Но такой запрос:

select * from parent_table where date = '2015-07-01'

использует индекс.

EXPLAIN результат:

    Append  (cost=0.00..30400.95 rows=107602 width=128)
->  Seq Scan on parent_table  (cost=0.00..0.00 rows=1 width=640)
    Filter: (date = '2015-07-01'::date)
->  Index Scan using z_partition_2015_07_date on z_partition_2015_07  (cost=0.43..30400.95 rows=107601 width=128)
    Index Cond: (date = '2015-07-01'::date)

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

Что-нибудь особенное, что мы должны сделать с индексом многораздельной таблицы?


person hudarsono    schedule 06.04.2016    source источник
comment
попробуйте использовать дату между условием   -  person Adam Silenko    schedule 06.04.2016
comment
Покажите объяснение, проанализируйте планы для них обоих.   -  person Jakub Kania    schedule 06.04.2016
comment
Трудно сказать, не зная о размере ваших данных и их структуре. Прежде всего попробуйте VACUUM ANALYZE parent_table собрать статистику по вашей многораздельной таблице. Если не помогло, попробуйте psql SET enable_seqscan = off и повторите свой запрос. Планировщику следует использовать сканирование индекса, чтобы вы могли сравнить затраты на сканирование seqscan и indexscan. Скорее всего, для этого типа запроса seqscan просто дешевле. Indexscan не очень хорош для получения больших объемов данных.   -  person Ildar Musin    schedule 06.04.2016
comment
@AdamSilenko По-прежнему то же самое с между   -  person hudarsono    schedule 06.04.2016
comment
@Musin Да, раздел содержит около 3 миллионов строк, и запрос заберет около 10% из них.   -  person hudarsono    schedule 06.04.2016
comment
вероятно ответ этот вопрос будет полезным (похоже на вашу проблему)   -  person Adam Silenko    schedule 06.04.2016
comment
Запустите SET enable_seqscan = off, а затем explain select * from parent_table where date >= '2015-07-01'. Это стоит больше, чем seqscan?   -  person Ildar Musin    schedule 06.04.2016


Ответы (2)


Я предполагаю, что вы знаете, что «разделы» - это отдельные таблицы в Postgres. Индексы обычно не используются при извлечении больших частей таблицы (более ~ 5%, это зависит от многих деталей), потому что обычно быстрее просто сканировать таблицу последовательно. в таких случаях.

Более того, похоже, что вы выбрали все строки из задействованных секций в своем первом запросе. Не использовать индексы ...

Как правило, предикат равенства с = более избирательный, чем предикат с >=. Подумайте об этом:

Ваш первый запрос с date >= '2015-07-01' извлекает все строки из раздела (предполагаю, мне нужно было бы увидеть точное определение). Использование индекса только увеличило бы накладные расходы. Но ваш второй запрос с date = '2015-07-01' возвращает только небольшой процент. Postgres ожидает, что сканирование индекса будет быстрее.

person Erwin Brandstetter    schedule 06.04.2016

может это просто так быстрее? запустите свой запрос, а затем сделайте следующее:

SET enable_seqscan=false

И снова запустить.

person murison    schedule 06.04.2016