@WellWisher

Как оптимизаровать запрос в postgresql c фильтрацией и сортировкой?

Есть базовая таблица (условно)
entities (id serial, value dp, date timestamp);

Хочется максимально оптимизировать запросы вида:
SELECT * FROM entities WHERE value = __VALUE__ ORDER BY date ASC NULLS LAST

Где __VALUE__ некое dp число, которое представлено в таблице.

Пробовал различные варианты:
  1. добавление индекса на value
  2. добавление индекса на date
  3. добавление мультиколоночных индексов (value, date) и (date, value)


На мой взгляд, единственный рабочий индекс из четырех:
- индекс на поле value

Собственно вопрос, можно ли добиться лучшей производительности и почему индекс (value, date) не работает?
Т.е. сейчас оптимизирована лишь выборка данных а не их сортировка.

Сведения о данных:
  • Записей в таблице - миллиард
  • Все ключи - обычные btree
  • Фильтр конкретному значению __VALUE__ возвращает около 250 тысяч записей (т.е. индекс эффективен).
  • Индексы создавались с соответствующими сортировками


Сведения о системе:
  • postgresql 9.3 или (9.4)
  • настройки по-умолчанию
  • с параметрами памяти для сортировок игрался, но добиться использования индекса так и не смог


Да, можно видоизменить запрос, и добавить что-то вроде LIMIT в конце, тогда помогает индекc (date, value), но он становится не эффективным, тогда помимо LIMIT в этом же запросе появляется OFFSET
  • Вопрос задан
  • 2535 просмотров
Пригласить эксперта
Ответы на вопрос 3
igruschkafox
@igruschkafox
Специалист по сопровождению БД MS SQL
я бы попробовал следующий вариант

если возможно то кластерным индексом отсортировать таблицу по - date ASC
Но надо быть осторожным что бы не затормозить другие запросы (в которых может быть DESC сортировка по дате)
и создать индекс по полю value

и почему индекс (value, date) не работает?

поиск то происходит по полю "value" а не по сочитанию полей
поле "date" - используется только для сортировки результата, а не отбора --- Поэтому и не работает составной индекс
Ответ написан
@Swartalf
>Записей в таблице - миллиард

А партиционирование у нас используется? если нет, то советую www.postgresql.org/docs/9.1/static/ddl-partitionin...
Ответ написан
@kshvakov
Вообще вся эта штука сильно зависит от селективности, если данных по value много постгрес может решить что "посортировать так" это эффективнее, в общем же случае индекс будет использоваться

т.к. "настройки по-умолчанию" сами сделайте analyze для entities, т.к. скорее всего постгрес не в курсе как у вас там данные по таблице распределены и "полюет на все фулсканом"

ps:

create table entities (id serial, value int, date timestamp);

create index idx_order on entities (value, date asc nulls last);


insert into entities (value, date)
select 
generate_series(1, 20),
time
from generate_series(date_trunc('day', current_timestamp - '10 day'::interval), date_trunc('day', current_timestamp ), '1 second') as time;


analyze entities;


explain SELECT * FROM entities WHERE value = 10 ORDER BY date ASC NULLS LAST


Sort  (cost=239331.74..241545.03 rows=885318 width=16)
  Sort Key: date
  ->  Bitmap Heap Scan on entities  (cost=32277.78..136750.25 rows=885318 width=16)
        Recheck Cond: (value = 10)
        ->  Bitmap Index Scan on idx_order  (cost=0.00..32056.45 rows=885318 width=0)
              Index Cond: (value = 10)


truncate entities;

insert into entities (value, date)
select 
generate_series(1, 200),
time
from generate_series(date_trunc('day', current_timestamp - '1 day'::interval), date_trunc('day', current_timestamp ), '1 second') as time;

analyze entities;


explain SELECT * FROM entities WHERE value = 10 ORDER BY date ASC NULLS LAST;

Sort  (cost=106726.86..106942.86 rows=86401 width=16)
  Sort Key: date
  ->  Bitmap Heap Scan on entities  (cost=3202.17..99642.51 rows=86401 width=16)
        Recheck Cond: (value = 10)
        ->  Bitmap Index Scan on idx_order  (cost=0.00..3180.57 rows=86401 width=0)
              Index Cond: (value = 10)



explain analyze SELECT * FROM entities WHERE value = 10 ORDER BY date ASC NULLS LAST;

Sort  (cost=106726.86..106942.86 rows=86401 width=16) (actual time=18774.148..18783.923 rows=86401 loops=1)
  Sort Key: date
  Sort Method: external sort  Disk: 2200kB
  ->  Bitmap Heap Scan on entities  (cost=3202.17..99642.51 rows=86401 width=16) (actual time=2618.908..18681.170 rows=86401 loops=1)
        Recheck Cond: (value = 10)
        Rows Removed by Index Recheck: 9708392
        Heap Blocks: exact=33638 lossy=52763
        ->  Bitmap Index Scan on idx_order  (cost=0.00..3180.57 rows=86401 width=0) (actual time=2611.946..2611.946 rows=86401 loops=1)
              Index Cond: (value = 10)
Planning time: 0.093 ms
Execution time: 18788.452 ms


set work_mem='1GB';

explain analyze SELECT * FROM entities WHERE value = 10 ORDER BY date ASC NULLS LAST;

Sort  (cost=106726.86..106942.86 rows=86401 width=16) (actual time=614.335..619.024 rows=86401 loops=1)
  Sort Key: date
  Sort Method: quicksort  Memory: 7123kB
  ->  Bitmap Heap Scan on entities  (cost=3202.17..99642.51 rows=86401 width=16) (actual time=198.700..595.232 rows=86401 loops=1)
        Recheck Cond: (value = 10)
        Heap Blocks: exact=86401
        ->  Bitmap Index Scan on idx_order  (cost=0.00..3180.57 rows=86401 width=0) (actual time=177.392..177.392 rows=86401 loops=1)
              Index Cond: (value = 10)
Planning time: 0.145 ms
Execution time: 623.327 ms
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы