|
Неоптимальный план запроса
|
|||
---|---|---|---|
#18+
Здравствуйте! Столкнулся с тем, что Postgres неоптимально выбирает план. Запрос: select servicecal0_.id as col_0_0_, employee1_.id as col_1_0_, servicecal0_.title as col_2_0_, servicecal0_.removed as col_3_0_, servicecal0_.removal_date as col_4_0_, servicecal0_.case_id as col_5_0_ from public.tbl_servicecall servicecal0_ inner join public.tbl_employee employee1_ on servicecal0_.author_id=employee1_.id where employee1_.id in (443891218) order by servicecal0_.id asc limit 21 Есть индекс idx_abstractus0 по таблице tbl_servicecall (id, title, removed, removal_date, case_id, route, clientemployee_id); План запроса: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14.
Если указать планировщику не использовать сканирование индекса, получаю приемлемое время выполнения: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21.
Статистику перестраивал, увеличивал значение default_statistics_target. Стоимости операций в конфигурации выставлены по умолчанию. Подскажите, пожалуйста, в чем может быть дело. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.09.2018, 17:12 |
|
Неоптимальный план запроса
|
|||
---|---|---|---|
#18+
Vladimir Yanchenko, А что говорит select count(*), count(*) filter (where author_id = 443891218), min(id), min(id) filter (where author_id = 443891218) from tbl_servicecall; ? И всегда делайте explain (ANALYZE, COSTS, BUFFERS, TIMING) а не explain analyze иначе не понять там с CPU плохо или диск тормозит. -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
10.09.2018, 18:22 |
|
Неоптимальный план запроса
|
|||
---|---|---|---|
#18+
Maxim Boguk, спасибо за ответ. Переделал план рекомендуемой командой: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21.
Вывод запроса: select count(*), count(*) filter (where author_id = 443891218), min(id), min(id) filter (where author_id = 443891218) from tbl_servicecall; count | count | min | min ---------+-------+---------+----------- 4116804 | 6904 | 1728402 | 447887574 ... |
|||
:
Нравится:
Не нравится:
|
|||
10.09.2018, 19:42 |
|
Неоптимальный план запроса
|
|||
---|---|---|---|
#18+
Vladimir Yanchenko, Теперь смотрим на проблему: всего строк 4116804 из них 6904 с нужным ID если бы у вас author_id располагался равномерно по диапазону ID то для выбора 21 строки по author_id = 443891218 order by id asc limit 21 базе бы понадобилось просмотреть (4116804/6904)*21 = 12516 строки по факту же база просматривает Rows Removed by Filter: 2295008 строк (т.е. пол таблицы или в 200 раз больше). Отсюда и тормоза. Называется скрытая корреляция между данными. Если у вас 10тая версия то может помочь CREATE STATISTICS IF NOT EXISTS tbl_servicecall_author_id_id_correlation ON id, author_id FROM tbl_servicecall; analyze tbl_servicecall; PS: а может и не помочь но сделана она в 10той версии как раз для этого. PPS: для версий до 10той я бы переделал запрос на order by servicecal0_.id+0 asc limit 21 чтобы убрать неудачный план. Но такая версия запроса будет себя плохо очень вести если у какого то из author_id будет очень много строк в таблице (тогда тот план что у вас быстрый - станет ОЧЕНЬ медленным). -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
10.09.2018, 20:00 |
|
Неоптимальный план запроса
|
|||
---|---|---|---|
#18+
Vladimir Yanchenko, могабыть сделать индекс по (author_id, id ) и запинать план на него. если в author_id in () множество, но небольшое, авторов -- пинать потипу лузскана с предфильтрацией не более 21 на рыло и ручным речеком после слияния если авторов в ине великое множество -- то вернуться к изначальному запросу. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.09.2018, 21:11 |
|
Неоптимальный план запроса
|
|||
---|---|---|---|
#18+
CREATE STATISTICS IF NOT EXISTS tbl_servicecall_author_id_id_correlation ON id, author_id FROM tbl_servicecall; analyze tbl_servicecall; Создание статистики не поменяло план. Создал индекс по (author_id, id ). Также без результатов. author_id в строке tbl_servicecall может быть только один, это ORM использует конструкцию IN. Попробовал тот же запрос с другими значениями author_id. Действительно, если в индексе нужно перебрать только небольшую часть значений, запрос по нашему "проблемному" плану выполняется быстро. Проблема возникает только на некоторых значениях, когда нужно пересмотреть значительную часть индекса. Неужели нет возможности уточнить статистику по распределению значений в индексе? Кстати, при смене порядка сортировки выбирается другой план, и запрос выполняется за 277 мс. Код: sql 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.
... |
|||
:
Нравится:
Не нравится:
|
|||
11.09.2018, 11:15 |
|
Неоптимальный план запроса
|
|||
---|---|---|---|
#18+
Vladimir Yanchenko, >>Неужели нет возможности уточнить статистику по распределению значений в индексе? Это не распределение значение а тайное знание что author_id = 443891218 в начале таблицы public.tbl_servicecall отсутствует вообще... тут даже не ясно в каком виде подобную информацию собирать и хранить увы... Может например быть первая запись с этим author_id в первых 100 строках по id таблицы а оставшиеся 20 в самом конце таблицы и что дальше делать? >>Создал индекс по (author_id, id ). Также без результатов. А если переписать запрос как: Код: plsql 1.
то какой план получается с индексом индексом по (author_id, id )? оно с этим индексом лучше не становится? зачем вообще в этом запросе join c public.tbl_employee ??? И если уж вам ну очень хочется join оставить то вот так вот сделать попробовать Код: plsql 1.
-- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
11.09.2018, 12:16 |
|
Неоптимальный план запроса
|
|||
---|---|---|---|
#18+
Maxim Boguk, Спасибо за помощь! Я думал, что за отображение местоположения значений (рядом - не рядом) отвечает столбец correlation в pg_stats. Видимо это немного не то. Предложенные запросы действительно быстро отрабатывают с индексом: Код: sql 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.
Хотя с DISTINCT запрос не ускоряется: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16.
К сожалению, у нас не получается гибко менять запросы. Используется ORM, которая сама эти запросы составляет. ... |
|||
:
Нравится:
Не нравится:
|
|||
11.09.2018, 17:10 |
|
|
start [/forum/topic.php?fid=53&msg=39700630&tid=1995596]: |
0ms |
get settings: |
10ms |
get forum list: |
12ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
46ms |
get topic data: |
10ms |
get forum data: |
2ms |
get page messages: |
45ms |
get tp. blocked users: |
1ms |
others: | 258ms |
total: | 392ms |
0 / 0 |