powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Как ускорить SELECT с высокой вариативностью высокоселективных WHERE и сортировкой?
8 сообщений из 8, страница 1 из 1
Как ускорить SELECT с высокой вариативностью высокоселективных WHERE и сортировкой?
    #39664839
alega19
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Есть табличка T с полями A, B, C и D.
Тип полей не так важен, главное, что к ним применимы опреатры сравнения больше/меньше (int,float,timestamp,...).
Запросы к этой таблице имеют следующие вариации:
1) Всегда применяется сортировка (ASC или DESC) по одному любому полю из перечисленных.
2) Возможны ограничения min/max (как только min, только max, так и оба) для любых из перечисленных полей в любых комбинациях.

При определенном кол-ве строк всё работает медленно. В этом и проблема.

Что уже сделано:
1) Построены b-tree индексы по всем полям, что дало прекрасный результат в ускорении запросов где:
а) происходит только сортировка
б) вместе с сортировкой применяются низкоселективные ограничения
в) когда высокоселективное ограничение применяется к тому же полю, по которому идет сортировка
В принципе результат предсказуемый.

Наверное уже ясно когда возникают проблемы. А именно при высокоселективных ограничениях по полю, отличному от поля сортировки.
Селективность таких ограничений может быть и нулевой. Тогда вообще труба.

Конкретика:
Код: plsql
1.
2.
3.
Limit  (cost=0.43..43.52 rows=2 width=20)
   ->  Index Scan Backward using communities_post_published_at_index on communities_post  (cost=0.43..779074.67 rows=36164 width=20)
         Filter: (views > 10000000)


Из EXPLAIN, как и ожидалось, Pg бежит по индексу поля сортировки (надеясь на низкую селективность ограничений?).
views > 10000000 - высокоселективный фильтр и высекает всего-то 64 записи из 4млн.
Хотя индекс по views тоже есть и конечно выгоднее было бы пробежать по нему. Но как видно Pg поступил иначе.

Думаю сделать частичные индексы:
create index "..._index" on T (col) where {expr};
где {expr} - высокоселективное условие по полю, отличному от col. Но я так задолбаюсь с:
1) Выяснением подходящего порога {expr}
2) В попытках не забыть все комбинации (col, {expr}) и на каждый построить индекс.
Здравый смысл, подсказывает, что Pg сам должен анализировать распределение по столбцам (хранить некоторые перцентили например) и из этой статы понимать когда бежать по индексу сортировки и применять фильтр условия, а когда по индексу условия и потом сортировать.
Т.е. банально имея хотя бы 0-ый и 100-ый перцентили можно ускорить все запросы с where col > {max of col} и where col < {min of col}. Хотя я не знаю как Pg хранит стату и работает с ней. Перцентили - лишь моё первое пришедшее на ум предположение.

Проблема не кажется мне уникальной. Как с ней бороться?
...
Рейтинг: 0 / 0
Как ускорить SELECT с высокой вариативностью высокоселективных WHERE и сортировкой?
    #39664844
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alega19,

А покажите что у вас показывает:

explain analyze select * from table where views > 10000000

что то странно чтобы база выбрала план что вы показали при "высокоселективный фильтр и высекает всего-то 64 записи из 4млн."

PS: что у вас с *_cost параметрами?
( select name,setting from pg_settings where name like '%_cost' order by name; )

--
Maxim Boguk
dataegret.ru
...
Рейтинг: 0 / 0
Как ускорить SELECT с высокой вариативностью высокоселективных WHERE и сортировкой?
    #39664856
alega19
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: plsql
1.
 explain analyze select id, published_at, vkid, community_id from communities_post where views > 10000000; -- Показывает:


автор Bitmap Heap Scan on communities_post (cost=683.11..89781.83 rows=36474 width=24) (actual time=0.178..4.924 rows=64 loops=1)
Recheck Cond: (views > 10000000)
Heap Blocks: exact=52
-> Bitmap Index Scan on communities_post_views_index (cost=0.00..673.99 rows=36474 width=0) (actual time=0.036..0.036 rows=65 loops=1)
Index Cond: (views > 10000000)
Planning time: 1.441 ms
Execution time: 5.004 ms

По views есть индекс, поэтому всё норм.

Проблема, когда столбец в where не совпадает со столбцом в orer by:
Код: plsql
1.
explain analyze select id, published_at, views from communities_post where views>10000001 order by published_at desc limit 500; -- Показывает:


автор Limit (cost=0.43..10432.98 rows=500 width=20) (actual time=41953.300..49853.537 rows=64 loops=1)
-> Index Scan Backward using communities_post_published_at_index on communities_post (cost=0.43..760846.33 rows=36465 width=20) (actual time=41953.291..49853.446 rows=64 loops=1)
Filter: (views > 10000001)
Rows Removed by Filter: 4332922
Planning time: 0.238 ms
Execution time: 49853.797 ms
Как я понимаю этот вывод - Pg сильно ошибается. Селективность всего 64 строки. Pg должен был предсказать это по гистограмме столбца views и не идти по индексу столбца published_at (сортировка), а идти по индексу столбца views.


Код: plsql
1.
select name,setting from pg_settings where name like '%_cost' order by name; -- Показывает:


автор name | setting
----------------------+---------
cpu_index_tuple_cost | 0.005
cpu_operator_cost | 0.0025
cpu_tuple_cost | 0.01
parallel_setup_cost | 1000
parallel_tuple_cost | 0.1
random_page_cost | 4
seq_page_cost | 1

ВАЖНО: я новичок, поэтому не исключайте глупых ошибок с моей стороны :)
...
Рейтинг: 0 / 0
Как ускорить SELECT с высокой вариативностью высокоселективных WHERE и сортировкой?
    #39664860
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alega19,

Проблема с
Код: plaintext
-> Bitmap Index Scan on communities_post_views_index (cost=0.00..673.99 rows=36474 width=0) (actual time=0.036..0.036 rows=65 loops=1)

rows=36474 vs rows=65
это не проблема выбора плана это проблема что у вас статистика не соответствует тому что в базе лежит
причем в данном случае почти на 3 порядка... не удивительно.


Попробуйте сделать сначала:
1)analyze verbose communities_post;
2)еще раз сделать
explain analyze select id, published_at, vkid, community_id from communities_post where views > 10000000;
и показать результаты.

3)show default_statistics_target ;


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Как ускорить SELECT с высокой вариативностью высокоселективных WHERE и сортировкой?
    #39664865
alega19
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ранее уже обновлял стату. Все-же сделал еще раз:
Код: plsql
1.
analyze verbose communities_post;


авторINFO: analyzing "public.communities_post"
INFO: "communities_post": scanned 30000 of 172480 pages, containing 756270 live rows and 105186 dead rows; 30000 rows in sample, 4348048 estimated total rows


Код: plsql
1.
explain analyze select id, published_at, vkid, community_id from communities_post where views > 10000000; -- ПоказываетЖ


авторBitmap Heap Scan on communities_post (cost=683.49..89894.95 rows=36524 width=24) (actual time=0.279..5.328 rows=64 loops=1)
Recheck Cond: (views > 10000000)
Heap Blocks: exact=52
-> Bitmap Index Scan on communities_post_views_index (cost=0.00..674.36 rows=36524 width=0) (actual time=0.022..0.022 rows=65 loops=1)
Index Cond: (views > 10000000)
Planning time: 1.124 ms
Execution time: 5.413 ms


Код: plsql
1.
show default_statistics_target; -- Показывает:


автор default_statistics_target
---------------------------
100
(1 row)


P.S: Ставил Pg 10.4 на Ubuntu 16.04 из официального репозитория от postgresql.org
Система (1 core, 1 Gb RAM, 30 Gb HDD) дохленькая но как я понял проблема не в ней.
postgresql.conf почти не менял:
автор#------------------------------------------------------------------------------
# RESOURCE USAGE (except WAL)
#------------------------------------------------------------------------------

# - Memory -

shared_buffers = 256MB # min 128kB
# (change requires restart)
#huge_pages = try # on, off, or try
# (change requires restart)
temp_buffers = 8MB # min 800kB
#max_prepared_transactions = 0 # zero disables the feature
# (change requires restart)
# Caution: it is not advisable to set max_prepared_transactions nonzero unless
# you actively intend to use prepared transactions.
work_mem = 4MB # min 64kB
maintenance_work_mem = 64MB # min 1MB
#replacement_sort_tuples = 150000 # limits use of replacement selection sort
#autovacuum_work_mem = -1 # min 1MB, or -1 to use maintenance_work_mem
max_stack_depth = 2MB # min 100kB
dynamic_shared_memory_type = posix # the default is the first option
# supported by the operating system:
# posix
# sysv
# windows
# mmap
# use none to disable dynamic shared memory
# (change requires restart)

# - Disk -

#temp_file_limit = -1 # limits per-process temp file space
# in kB, or -1 for no limit

# - Kernel Resource Usage -

#max_files_per_process = 1000 # min 25
# (change requires restart)
#shared_preload_libraries = '' # (change requires restart)

# - Cost-Based Vacuum Delay -

#vacuum_cost_delay = 0 # 0-100 milliseconds
#vacuum_cost_page_hit = 1 # 0-10000 credits
#vacuum_cost_page_miss = 10 # 0-10000 credits
#vacuum_cost_page_dirty = 20 # 0-10000 credits
#vacuum_cost_limit = 200 # 1-10000 credits

# - Background Writer -

#bgwriter_delay = 200ms # 10-10000ms between rounds
#bgwriter_lru_maxpages = 100 # 0-1000 max buffers written/round
#bgwriter_lru_multiplier = 2.0 # 0-10.0 multiplier on buffers scanned/round
#bgwriter_flush_after = 512kB # measured in pages, 0 disables

# - Asynchronous Behavior -

#effective_io_concurrency = 1 # 1-1000; 0 disables prefetching
#max_worker_processes = 8 # (change requires restart)
#max_parallel_workers_per_gather = 2 # taken from max_parallel_workers
#max_parallel_workers = 8 # maximum number of max_worker_processes that
# can be used in parallel queries
#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate
# (change requires restart)
#backend_flush_after = 0 # measured in pages, 0 disables
...
Рейтинг: 0 / 0
Как ускорить SELECT с высокой вариативностью высокоселективных WHERE и сортировкой?
    #39664902
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alega19,

При таком размере таблицы стоит поднять default_statistics_target до 1000 или даже до 10000.
(потом перечитать конфиг, еще раз сделать analyze таблицы, И еще раз explain analyze)
У вас проблема с недостаточным размером выборки при построении статистики отчего получается кривая гистограмма (на ее хвостах).

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Как ускорить SELECT с высокой вариативностью высокоселективных WHERE и сортировкой?
    #39665017
alega19
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Maxim Boguk,

Точно!
Залез в postgresql.conf и установил default_statistics_target = 1000
Код: plsql
1.
2.
3.
select pg_reload_conf(); -- из под superuser
analyze;
explain analyze select id, published_at, vkid, community_id from communities_post where views > 10000000; -- Показывает:


Код: plaintext
1.
2.
3.
4.
5.
6.
 Bitmap Heap Scan on communities_post  (cost=91.59..12563.06 rows=3504 width=24) (actual time=0.038..0.402 rows=65 loops=1)
   Recheck Cond: (views > 10000000)
   Heap Blocks: exact=56
   ->  Bitmap Index Scan on communities_post_views_index  (cost=0.00..90.71 rows=3504 width=0) (actual time=0.022..0.022 rows=73 loops=1)
         Index Cond: (views > 10000000)
 Planning time: 0.665 ms
 Execution time: 0.503 ms

И теперь мой первоначальный запрос
Код: plsql
1.
explain analyze select id, published_at, views from communities_post where views>10000000 order by published_at desc limit 500; -- Выбирает разумный план:


Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
 Limit  (cost=12737.66..12738.91 rows=500 width=20) (actual time=0.889..0.899 rows=65 loops=1)
   ->  Sort  (cost=12737.66..12746.42 rows=3504 width=20) (actual time=0.888..0.892 rows=65 loops=1)
         Sort Key: published_at DESC
         Sort Method: quicksort  Memory: 30kB
         ->  Bitmap Heap Scan on communities_post  (cost=91.59..12563.06 rows=3504 width=20) (actual time=0.057..0.740 rows=65 loops=1)
               Recheck Cond: (views > 10000000)
               Heap Blocks: exact=56
               ->  Bitmap Index Scan on communities_post_views_index  (cost=0.00..90.71 rows=3504 width=0) (actual time=0.037..0.037 rows=73 loops=1)
                     Index Cond: (views > 10000000)
 Planning time: 0.442 ms
 Execution time: 0.950 ms
Спасибо.

Интересен один момент.
Вы сказали
Maxim Boguk... При таком размере таблицы стоит поднять default_statistics_target до 1000 или даже до 10000...
И действительно сейчас я наблюдаю всё еще немалую ошибку rows=3504 vs rows=65. Как я понимаю показатель default_statistics_target коррелирует с количеством строк в таблице. Но 10000 - это возможный максимум, в то время как в моей табличке всего 4млн строк. А как люди живут, когда в таблице строк на порядок/порядки больше чем в моей?
...
Рейтинг: 0 / 0
Как ускорить SELECT с высокой вариативностью высокоселективных WHERE и сортировкой?
    #39665034
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alega19Интересен один момент.
Вы сказали
Maxim Boguk... При таком размере таблицы стоит поднять default_statistics_target до 1000 или даже до 10000...
И действительно сейчас я наблюдаю всё еще немалую ошибку rows=3504 vs rows=65. Как я понимаю показатель default_statistics_target коррелирует с количеством строк в таблице. Но 10000 - это возможный максимум, в то время как в моей табличке всего 4млн строк. А как люди живут, когда в таблице строк на порядок/порядки больше чем в моей?

На таблице в 400M строк даже оценка rows=60000 скорее всего дали бы разумный план.
А на практике - на границах гистограммы распределения данных всегда могут быть чудеса с планом (уж так оно устроено).

Вы на самом деле не того боитесь.
Стоит боятся ситуации когда строк подходящих под условие много но не очень много...
и где на выходе получается ситуации когда и через:
sort + bitmap scan искать не очень быстро (потому что строк все таки ну скажем 100.000 подходит)
и через Index Scan Backward тоже не очень быстро потому что ваши 100.000 составляют очень малую долю в таблице.
Но это проблема когда в таблице 100M или 1000M строк чаще всего вылезает.
Но с этим уже только жить остается.

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
8 сообщений из 8, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Как ускорить SELECT с высокой вариативностью высокоселективных WHERE и сортировкой?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]