Лучший подход для получения упорядоченных данных из большой таблицы

#postgresql #sql-order-by

Вопрос:

Я пытаюсь получить упорядоченные и отфильтрованные данные из таблицы с 10 миллионами строк. Проблема ordered by в том, что в этом случае работа идет очень медленно. Количество комбинаций фильтрации очень велико, я не могу предсказать, что все они создадут кэш в правильном порядке. Кроме того, мои данные могут часто изменяться. Другими словами, мне действительно нужно сортировать свои данные с каждым запросом.

Я попытался погуглить его и понял, что индексы и другие оптимизации не могут быть полезны для заказа. Я прав? И каков наилучший способ быстро получить упорядоченные данные? Возможно ли это в постгресе? Должен ли я использовать для этого другие инструменты? Может быть, ETL в нереляционной БД или что-то в этом роде?

пример простого запроса:

 EXPLAIN ANALYZE SELECT * FROM offers WHERE  offers.attributes -gt;gt; 'width' = '190'  AND offers.attributes -gt;gt; 'height' = '55'  AND offers.attributes -gt;gt; 'diameter' = '16' ORDER BY price  

объясните, проанализируйте вывод:

 Sort (cost=463529.78..463529.78 rows=1 width=248) (actual time=3083.447..3084.143 rows=12420 loops=1)  Sort Key: price  Sort Method: quicksort Memory: 6530kB  -gt; Gather (cost=1000.00..463529.77 rows=1 width=248) (actual time=0.327..3078.755 rows=12420 loops=1)  Workers Planned: 2  Workers Launched: 2  -gt; Parallel Seq Scan on offers (cost=0.00..462529.67 rows=1 width=248) (actual time=4.826..3072.672 rows=4140 loops=3)  Filter: (((attributes -gt;gt; 'width'::text) = '190'::text) AND ((attributes -gt;gt; 'height'::text) = '55'::text) AND ((attributes -gt;gt; 'diameter'::text) = '16'::text))  Rows Removed by Filter: 3329193 Planning Time: 0.256 ms Execution Time: 3084.612 ms  

все индексы таблиц

 create index offers_attribu_5d15b4_gin  on offers using gin (attributes);  create index offers_created_ae6fa523  on offers (created);  create index offers_updated_c723e738  on offers (updated);  create index offers_quantity_dc0026a6  on offers (quantity);  create index offers_model_id_8846a913  on offers (model_id);  create index offers_price_list_id_1f3d95de  on offers (price_list_id);  create index offers_price_ids  on offers (price);  create index offers_model_price_idx  on offers (model_id, price);  create index offers_json_price_idx  on offers (attributes, price);  create index offers_json_model_idx  on offers (attributes, model_id);  create index offers_price_idx  on offers (price);  

Комментарии:

1. «Количество комбинаций фильтрации очень велико», но как насчет избирательности? Если одно условие устраняет 99,999% данных, а все остальные вместе взятые удаляют только 50% того, что осталось, вы можете в значительной степени игнорировать остальные условия.

2. @a_horse_with_no_name готово

3. @jjanes после фильтрации осталось около 100 тысяч строк

4. @jjanes, конечно, зависит от фильтров, например, может быть 10 000, но это все равно медленно

5. В вашем примере сортировка заняла гораздо меньше 1% от общего времени. Не стоит беспокоиться об этом.

Ответ №1:

Ваш запрос станет быстрее, если вы перепишете его так, чтобы он мог использовать индекс GIN в jsonb столбце:

 SELECT * FROM offers WHERE attributes @gt; '{ "width": 190, "height": 55, "diameter": 16 }' ORDER BY price;