|
план выполнения (most_common_freqs и игнор селективности лидирующих полей индекса)
|
|||
---|---|---|---|
#18+
Есть таблица 3,6 млн записей, есть индекс по трем полям. Выборка из этой таблицы с условием по этим трем полям использует индекс. EXPLAIN показывает, что ожидается три записи в выборке, по факту имеем одну. Берем и присоединяем к этой выборке (по тем же условиям) другую таблицу (очень большую) по первому полю одного из её индексов. И теперь постгрес из первой таблицы достает данные через Parallel Seq Scan (конечно же, медленно). А потом уже делает для каждого из трех воркеров Nested Loop. Засовываю выборку из первой таблицы в материализованное CTE, и всё работает как надо. По поводу индекса и условий отбора: значения для второго и третьего полей индекса отметились в стате с most_common_freqs 0.43 и 0.42 соответственно. Но значение для первого поля (тоже просто константа в запросе) в стате не отметилось и, собсно, решает. В опыте выше достаточно указать в условии для третьего(!) поля индекса значение с низкой частотой, чтобы индекс начал работать. Почему постгрес так делает? Как заставить его применить индекс без вытаскивания части выборки в материализованное CTE? ... |
|||
:
Нравится:
Не нравится:
|
|||
26.10.2021, 20:37 |
|
план выполнения (most_common_freqs и игнор селективности лидирующих полей индекса)
|
|||
---|---|---|---|
#18+
aceton Есть таблица 3,6 млн записей, есть индекс по трем полям. Выборка из этой таблицы с условием по этим трем полям использует индекс. EXPLAIN показывает, что ожидается три записи в выборке, по факту имеем одну. Берем и присоединяем к этой выборке (по тем же условиям) другую таблицу (очень большую) по первому полю одного из её индексов. И теперь постгрес из первой таблицы достает данные через Parallel Seq Scan (конечно же, медленно). А потом уже делает для каждого из трех воркеров Nested Loop. Засовываю выборку из первой таблицы в материализованное CTE, и всё работает как надо. По поводу индекса и условий отбора: значения для второго и третьего полей индекса отметились в стате с most_common_freqs 0.43 и 0.42 соответственно. Но значение для первого поля (тоже просто константа в запросе) в стате не отметилось и, собсно, решает. В опыте выше достаточно указать в условии для третьего(!) поля индекса значение с низкой частотой, чтобы индекс начал работать. Почему постгрес так делает? Как заставить его применить индекс без вытаскивания части выборки в материализованное CTE? Если не сложно покажите запрос целиком и план (тоже целиком). Я тогда смогу предметно позадавать вопросы и посоветовать. Первоначальное предположение (исходя из "значение для первого поля (тоже просто константа в запросе) в стате не отметилось") у вас кривая оценка количества distinct значений в этом поле. А это достаточно легко фиксится. -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
27.10.2021, 12:30 |
|
план выполнения (most_common_freqs и игнор селективности лидирующих полей индекса)
|
|||
---|---|---|---|
#18+
Оценка distinct-значений не кривая. EXPLAIN простой выборки с условием только по первому полю индекса предсказывает 18 записей. Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58.
... |
|||
:
Нравится:
Не нравится:
|
|||
27.10.2021, 14:34 |
|
план выполнения (most_common_freqs и игнор селективности лидирующих полей индекса)
|
|||
---|---|---|---|
#18+
aceton, Проблема находится в районе строчки -- -> Index Scan using post_0_0_debit_id_ts_idx on post_0_0 p (cost=0.70..8580683.44 rows=8392877 width=61) (actual time=0.055..0.055 rows=0 loops=1) -- Index Cond: (debit_id = a.id) База думает что по debit_id = a.id будем 8М строк а на самом деле 0. Что у вас с распределением данных debit_id в таблице post_0_0 ? Если не сложно select count(*), count(debit_id), count(distinct debit_id) from post_0_0; и select cout(*), debit_id from post_0_0 group by debit_id order by 1 desc limit 10; покажите. У вас там явно какое то неожиданное распределение данных если база настолько ошибается в оценке селективности. -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
27.10.2021, 15:27 |
|
план выполнения (most_common_freqs и игнор селективности лидирующих полей индекса)
|
|||
---|---|---|---|
#18+
Maxim Boguk, Таблица post_0_0 большая 226Gb и 2.6e9 записей (так в стате, но похоже на правду), n_distinct для debit_id - 310 (analyze делал). Но ведь речь о выборке из main.account. У нас в обоих ситуациях nested loop - и с CTE, и без. И еще вот это: авторВ опыте выше достаточно указать в условии для третьего(!) поля индекса значение с низкой частотой, чтобы индекс начал работать. И это тоже про main.account и про его индекс, который оказался по непонятным причинам в игноре. Запрошенные выборки из post_0_0 сделать весьма проблематично. ... |
|||
:
Нравится:
Не нравится:
|
|||
27.10.2021, 17:56 |
|
план выполнения (most_common_freqs и игнор селективности лидирующих полей индекса)
|
|||
---|---|---|---|
#18+
aceton Maxim Boguk, Таблица post_0_0 большая 226Gb и 2.6e9 записей (так в стате, но похоже на правду), n_distinct для debit_id - 310 (analyze делал). Но ведь речь о выборке из main.account. У нас в обоих ситуациях nested loop - и с CTE, и без. И еще вот это: авторВ опыте выше достаточно указать в условии для третьего(!) поля индекса значение с низкой частотой, чтобы индекс начал работать. И это тоже про main.account и про его индекс, который оказался по непонятным причинам в игноре. Запрошенные выборки из post_0_0 сделать весьма проблематично. Индекс не оказался в игноре... цена запроса через CTE в 3 раза больше чем через parralel seq scan cost=5.37..25993541.06 vs cost=1000.71..8769077.25 и если бы база УМЕЛА parralel CTE scan - она бы его применила. Аналогично если бы в ответе было не 0 строк а ожидаемые 30M cтрок - запрос с seq scan и паралельным выполнением был бы вероятно быстрее. Из имеющихся у базы данных она строит разумный план. Она никак не может знать что в post_0_0 по найденному a.id будет ноль строк. -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
27.10.2021, 18:31 |
|
план выполнения (most_common_freqs и игнор селективности лидирующих полей индекса)
|
|||
---|---|---|---|
#18+
aceton, А какая версия базы у вас? Тут в принципе parralel index scan напрашивается. -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
27.10.2021, 18:43 |
|
план выполнения (most_common_freqs и игнор селективности лидирующих полей индекса)
|
|||
---|---|---|---|
#18+
Maxim Boguk, PostgreSQL v.12.4 (Ubuntu 12.4-1.pgdg18.04+1) Я что-то нить потерял. Сервер решил получить данные из одного источника, а потом для каждой строчки поискать в другом. Первый - account. Условия одинаковые при обычной выборке и при выборке с дальнейшим Nested Loop. На этом этапе при чем здесь post_0_0? Как он насчитал такую стоимость через CTE относительно прямого варианта? Если я в условии поиска по account поменяю значение третьей(!) колонки в индексе (currency) на значение с маленьким most_common_freqs, то запрос без CTE применяет индекс. Повторюсь - выборка просто по owner_id ожидается в количестве 18 записей . Это первое поле индекса. ... |
|||
:
Нравится:
Не нравится:
|
|||
27.10.2021, 19:20 |
|
план выполнения (most_common_freqs и игнор селективности лидирующих полей индекса)
|
|||
---|---|---|---|
#18+
aceton Maxim Boguk, PostgreSQL v.12.4 (Ubuntu 12.4-1.pgdg18.04+1) Я что-то нить потерял. Сервер решил получить данные из одного источника, а потом для каждой строчки поискать в другом. Первый - account. Условия одинаковые при обычной выборке и при выборке с дальнейшим Nested Loop. На этом этапе при чем здесь post_0_0? Как он насчитал такую стоимость через CTE относительно прямого варианта? Если я в условии поиска по account поменяю значение третьей(!) колонки в индексе (currency) на значение с маленьким most_common_freqs, то запрос без CTE применяет индекс. Повторюсь - выборка просто по owner_id ожидается в количестве 18 записей . Это первое поле индекса. Смотрите база думает что по условию where a.owner_id = 12345 and a.code = 2411::int2 and a.currency = 'TEST' будет 3 строки выбрано и для каждой из них будет выбрано по 8M строк по условию (debit_id = a.id) сама выборка этих 8М строк - штука крайне тяжелая поэтому логично запустить параллельное выполнение этого запроса чтобы эти выборки по 8М строк выбирались в несколько потоков. Но 12 версия НЕ УМЕЕТ в parralel index scan а только в parralel seq scan, поэтому база логично делает паралельный seq scan по main.account. Через CTE такая стоимость потому что база не может в 12 версии паралельное выполнение запроса включить на такой ситуации. И честно насчитывает цену в 3 раза выше. Если же "Если я в условии поиска по account поменяю значение третьей(!) колонки в индексе (currency) на значение с маленьким most_common_freqs" база решит что по набору условий where a.owner_id = 12345 and a.code = 2411::int2 and a.currency = чтототам будет не 3 строки а 1 строка и в такой ситуации параллеьный join смысла делать нет. Возможно тут бы помогло создание расширеной статисткики по полям owner_id,code,currency для уточнения прогноза по этим условиям. PS: в таких случаях как ни странно часто лучший выход разбивать на 2 запроса (сначала выбирать a.id нужные а потом main.post по where IN (список) для получения разумных планов если у вас данные очень неровно расположены. -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 10:19 |
|
план выполнения (most_common_freqs и игнор селективности лидирующих полей индекса)
|
|||
---|---|---|---|
#18+
Maxim Boguk, Если выборка из post_0_0 показалась тяжелой, то почему не выполнять параллельно узел чтения из post_0_0 вместо раскладывания на воркеры всего запроса. Parallel Index Scan появился существенно раньше . В целом понятно, что субд вынужденно не применила параллельное выполнение и случайно выиграла. А когда хотела ускориться за счет распараллеливания, то промахнулась, но в рамках одного воркера при параллельной обработке выбор Seq Scan по счетам непонятен. Понятно, что можно поприседать и сделать быстро. Проблема в том, что поведение довольно неожиданное. Предсказывать его крайне затруднительно, а если все запросы разбивать на кусочки, то весь смысл теряется. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 11:25 |
|
план выполнения (most_common_freqs и игнор селективности лидирующих полей индекса)
|
|||
---|---|---|---|
#18+
aceton Maxim Boguk, Если выборка из post_0_0 показалась тяжелой, то почему не выполнять параллельно узел чтения из post_0_0 вместо раскладывания на воркеры всего запроса. Parallel Index Scan появился существенно раньше . В целом понятно, что субд вынужденно не применила параллельное выполнение и случайно выиграла. А когда хотела ускориться за счет распараллеливания, то промахнулась, но в рамках одного воркера при параллельной обработке выбор Seq Scan по счетам непонятен. Понятно, что можно поприседать и сделать быстро. Проблема в том, что поведение довольно неожиданное. Предсказывать его крайне затруднительно, а если все запросы разбивать на кусочки, то весь смысл теряется. Потому что параллельное выполнение в месте "выполнять параллельно узел чтения из post_0_0" база не умеет даже в 14той версии. PS: Поведение планировщика в случае кривой оценки статистики - оно малопредсказуемо. Более того на неожиданных для базы распределениях данных - с планами всегда будут чудеса, это свойство мира. И в общем задача dba и разработчика эти ситуации ловить и исправлять. -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 12:50 |
|
|
start [/forum/topic.php?fid=53&fpage=6&tid=1993807]: |
0ms |
get settings: |
11ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
28ms |
get topic data: |
13ms |
get forum data: |
3ms |
get page messages: |
52ms |
get tp. blocked users: |
2ms |
others: | 252ms |
total: | 383ms |
0 / 0 |