|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Коллеги, ткните пожалуйста носом в нужном направлении (речь про postgresql 9.6). Есть простой запрос вида: Код: plsql 1. 2. 3. 4. 5.
Который нам даёт такой страшный план (в табличке более 3.5 млрд. строк и время выполнения запроса соответственно - больше 20 минут, на ssd дисках и random_page_cost = 1.1): Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9.
При этом в табличке interview_question_details есть такой вот подходящий индекс: Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.
При этом, если в табличку добавить индекс только по interview_id - то планировщик сразу его выбирает и исходный запрос выполняется за несколько миллисекунд, которые и ожидались (индекс назвали fki_interviewquestiondetails_interviewid): Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.
Вопрос: почему планировщик не хочет использовать индекс по interview_id + question_number, но прекрасно берёт индекс по одному полю interview_id? При этом, если напишем запрос аля: Код: plsql 1.
то получим нормальный ожидаемый план запроса: Код: plaintext 1. 2.
Держать в таблице такого размера два, по сути одинаковых, индекса - очень накладно. ... |
|||
:
Нравится:
Не нравится:
|
|||
22.11.2019, 17:32 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Alexey Trizno, Вероятно план с доступом по индексу планировщик считает более дорогим. А покажите план, предварительно выключив: set enable_seqscan = off; ... |
|||
:
Нравится:
Не нравится:
|
|||
22.11.2019, 17:52 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
и сделайте explain (analyze) Alexey Trizno речь про postgresql 9.6 Alexey Trizno -> Parallel Bitmap Heap Scan on respondents r (cost=142.39..12763.80 rows=4905 width=8) А если не обманывать по поводу версии базы? В 9.6 в принципе parallel bitmap не было. Только parallel seqscan появился. ... |
|||
:
Нравится:
Не нравится:
|
|||
22.11.2019, 18:32 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Melkij, Каюсь про 9.6 - первый запрос из неё (это продовая база), а второй из копии этой базы на dev-сервере, там postgresql уже поновее. Но суть от этого не меняется, к сожалению :( Вот план первого запроса на той же базе и версии, что план с индексом по interview_id: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13.
На прод-базе (где 9.6) дождаться выполнения долго запроса с analyze - не получается вообще. Могу попробовать запустить ночью, если поможет. ... |
|||
:
Нравится:
Не нравится:
|
|||
22.11.2019, 18:51 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Павел Лузанов, отключение seqscan - да, помогает решить проблему: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8.
Это единственное решение в такой ситуации? ... |
|||
:
Нравится:
Не нравится:
|
|||
22.11.2019, 18:55 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Alexey Trizno, показывайте explain analyze ещё раз прошу. Не только для исходного, но и для быстрого плана. Понятно что план со стоимостью на порядок выше планировщику не нравится. Если по факту он быстрее - значит в какой-то момент планировщик ошибается, скорей всего по числу уникальных строк для interview_id. Stats target какой? ... |
|||
:
Нравится:
Не нравится:
|
|||
22.11.2019, 19:45 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Melkij, было не просто, но удалось выполнить analyze на продуктовой базе для основной ситуации, когда нет отдельного индекса по interview_id: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14.
default_statistics_target не менялся, т.е. сейчас 100 by default. ... |
|||
:
Нравится:
Не нравится:
|
|||
23.11.2019, 17:49 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Alexey Trizno, в продукции не хватает индекса `ON interview_question_details(interview_id)` ... |
|||
:
Нравится:
Не нравится:
|
|||
23.11.2019, 18:47 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
vyegorov, :) это да, он его хочет, но вопрос топика в другом - чем не нравится имеющийся индекс: Код: plsql 1.
Он есть и прекрасно, вроде бы, подходит, что подтверждается выполнением того же самого запроса при принудительно отключенном seqscan. Хочется понять проблему, т.к. у нас в базе, с целью экономии объема (только в этой одной таблице 3.5 млрд. записей и кол-во постоянно увеличивается), много подобных мест, когда сделаны индексы по нескольким полям, вместо пачки индексов с нарастающим кол-вом полей под все варианты выборок. Ведь чтобы не делать индексы по A+B+C, A+B, A - достаточно одного по A+B+C, при условии выборок по A, либо по A+B, либо по A+B+C. Согласно документации. Но... что-то сбивает планировщик запросов и он хочет отдельный индекс по A при выборке только по A. ... |
|||
:
Нравится:
Не нравится:
|
|||
23.11.2019, 18:58 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Alexey Trizno, Основная ошибка я думаю происходит изза ошибки на 3 порядка в этой части: -> Index Only Scan using ix_respondents_projectid_id on respondents r (cost=0.57..18779.68 rows=26597 width=8) (actual time=0.159..0.167 rows=9 loops=1) Index Cond: (project_id = 6) После этого уже на хороший план нет смысла рассчитывать. Что говорит (вот все 3 выполнить как я написал): Код: plsql 1. 2. 3.
Я подозреваю что начинать придется с проставления повышенного statistic_target (1000 - 10000) для respondents.project_id (и вероятнее всего с проставления n_distinct для него же). Возможно тоже самое надо будет сделать для interview_question_details.interview_id (но это будет понятно после того как мы оценку селективности для respondents поправим). ... |
|||
:
Нравится:
Не нравится:
|
|||
23.11.2019, 19:46 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Alexey Trizno Melkij, было не просто, но удалось выполнить analyze на продуктовой базе для основной ситуации, когда нет отдельного индекса по interview_id: второго explain analyze так и не увижу? Alexey Trizno -> Index Only Scan using ix_respondents_projectid_id on respondents r (cost=0.57..18779.68 rows=26597 width=8) (actual time=0.159..0.167 rows=9 loops=1) неплохо так расходится. Maxim Boguk опередил с ответом уже ... |
|||
:
Нравится:
Не нравится:
|
|||
23.11.2019, 19:49 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Maxim Boguk, Ок, по порядку: Код: plsql 1.
Код: plaintext 1. 2. 3. 4. 5.
Код: plsql 1.
Код: plsql 1.
Код: plaintext 1. 2. 3. 4. 5.
Вот как-то так. ... |
|||
:
Нравится:
Не нравится:
|
|||
23.11.2019, 19:54 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Melkij второго explain analyze так и не увижу? Я стараюсь, всё будет, но построить индекс новый по interview_id на продуктовой базе (чтобы уж всё было честно) - пока не получается. Поставлю сегодня после 23:00 его создание, там долго. В рабочее время начинает сильно проседать производительность. ... |
|||
:
Нравится:
Не нравится:
|
|||
23.11.2019, 19:56 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Alexey Trizno Maxim Boguk, Ок, по порядку: Код: plaintext 1. 2. 3. 4. 5.
При таких размерах таблиц я боюсь вам местами statistics_target надо будет очень сильно поднимать. попробуйте сделать (с неким запасом все задал): alter table respondents alter project_id set STATISTICS 10000; alter table respondents alter project_id set (n_distinct = 10000); analyze respondents; explain analyze select * from respondents where project_id = 6; и покажите план проблемного запроса после этого (без analyze), просто explain. ... |
|||
:
Нравится:
Не нравится:
|
|||
23.11.2019, 20:01 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Maxim Boguk, Выполнил. Код: plsql 1.
Код: plaintext 1. 2. 3. 4.
Код: plsql 1. 2. 3. 4. 5. 6.
Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8.
Индекс теперь используется. Можно пояснить что ему было не так и как жить дальше? :) У нас скоро будет сильное изменение схемы базы для возможности выделения данных проектов в отдельные базы и на отдельные сервера. Хотелось бы понять - что делаем не так? Вроде миллиарды записей в табличках - не так и много, в планах умножить эту цифру на много. В обычной работе такие запросы (как наш проблемный обсуждаемый) не используются - он появился как раз при работе мигратора в новую схему базы, для переноса данных всего проекта разом. Почему же такая ошибка в статистике? ... |
|||
:
Нравится:
Не нравится:
|
|||
23.11.2019, 21:14 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Alexey Trizno, Я бы еще порекомендовал бы сделать следующие запросы чтобы понимать ситуцию explain analyze select distinct interview_id from interview_question_details посмотрим насколько база ошибается в оценке количества уникальных interview_id ps; вообще проблема эффективной корректной оценки количества уникальных значений без вычитывания всей таблицы не очень разрешима алгоритмически к сожалению поэтому возня с ручной простановкой корректных n_distinct на очень больших таблицах для исправления проблемных планов она неустранима на данном этапе. pps: какие то странные цены у вас база на самом деле высчитывает кстати слишком уж дешевый seq_scan выходит что у вас показывает select name,setting from pg_settings where name like '%_cost' order by name; ? ... |
|||
:
Нравится:
Не нравится:
|
|||
24.11.2019, 01:58 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Alexey Trizno, кстати а что у вас показывает select project_id, count(*) from respondents group by project_id order by 2 desc limit 20; в ситуации когда в таблице 100 миллионов строк - корректно оценить сколько строк попадет под редкое условие (а project_id = 6 с его 9 строками - очевидно редкое) - тоже к сожалению не реально. Вот база и гадает как умеет. Проблема называется сильно неравномерное распределение данных (и тоже не имеет хорошего решения кроме решения проблем по месту). ... |
|||
:
Нравится:
Не нравится:
|
|||
24.11.2019, 02:03 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Maxim Boguk, Изначально (перешли на postgresql только года 3 как) база у нас была mssql и подобные проблемы решались просто указанием в запросах - какие индексы надо использовать, если планировщик ошибался. В postgresql такой возможности нет, вот и споткнулись, и теперь надо разбираться - как заставить планировщик выбрать нужное, более правильным и умным путем. В конфиге на тему cost: Код: plaintext 1. 2. 3. 4. 5. 6.
Диски в серверах под базу только ssd и скоро под часть данных будут nvme. Два запроса для анализа значений - выполню ночью, сейчас они опять же - полностью кладут базу :( ... |
|||
:
Нравится:
Не нравится:
|
|||
24.11.2019, 12:21 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Maxim Boguk, Вот второй запрос выполнился: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21.
... |
|||
:
Нравится:
Не нравится:
|
|||
24.11.2019, 12:22 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Alexey Trizno Maxim Boguk, Вот второй запрос выполнился: Код: plaintext 1. 2. 3. 4.
Ну вот для всех этих популярных project_id hash join скорее всего будет быстрее заметно чем nested loop и форсированное использование индекса бы ситуацию испортило. ps: а зачем вообще такой запрос используется? я вот с трудом понимаю в какой ситуации его могут выполнить с r.project_id = 4304 например и что после этого делать с результатами (которых будет очень много). по настройкам я бы скорее всего порекомендовал бы поднять cpu_tuple_cost до 0.1 или уменьшить random/seq _page_cost до 0.11/0.1 у вас база явно недооценивает цену перебора 3.5 миллиардов строк по cpu. Но могут какие то другие планы испортится так что надо осторожно. ... |
|||
:
Нравится:
Не нравится:
|
|||
24.11.2019, 12:57 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Maxim Boguk, Такой запрос - это для миграции базы в другую схему, т.е. массовый перенос данных по проектам с ремапингом всех id в памяти приложением. Т.е. ситуация - редкая. Сам вопрос возник именно из-за непонимания, почему так. Сейчас понимания уже стало побольше. "для всех этих популярных project_id hash join скорее всего будет быстрее заметно чем nested loop" - тут есть сомнение, т.к. он же пытался сканировать все 3.5 млрд, вместо например 600 тыс. строк (самое большо кол-во для project_id). сканировать 3.5 млрд всегда же будет медленнее (это почти 500Gb на диске, и просто даже прочитать такие данные... долго), чем пройтись по индексу. ... |
|||
:
Нравится:
Не нравится:
|
|||
24.11.2019, 15:49 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Alexey Trizno <> "для всех этих популярных project_id hash join скорее всего будет быстрее заметно чем nested loop" - тут есть сомнение, т.к. он же пытался сканировать все 3.5 млрд, вместо например 600 тыс. строк (самое большо кол-во для project_id). сканировать 3.5 млрд всегда же будет медленнее (это почти 500Gb на диске, и просто даже прочитать такие данные... долго), чем пройтись по индексу. покажите оценку костов: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13.
... |
|||
:
Нравится:
Не нравится:
|
|||
24.11.2019, 16:22 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Alexey Trizno "для всех этих популярных project_id hash join скорее всего будет быстрее заметно чем nested loop" - тут есть сомнение, т.к. он же пытался сканировать все 3.5 млрд, вместо например 600 тыс. строк (самое большо кол-во для project_id). сканировать 3.5 млрд всегда же будет медленнее (это почти 500Gb на диске, и просто даже прочитать такие данные... долго), чем пройтись по индексу. Вот чтобы это базе обьяснить более точно я и предлагал поднять cpu_tuple_cost (цену обработки 1 строки базой). + база судя по всему ожидаемо сильно недооценивает количество уникальных interview_id в interview_question_details и отсюда неверно оценивает сколько строк там будет получатся на выходе. ... |
|||
:
Нравится:
Не нравится:
|
|||
24.11.2019, 17:43 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
qwwq, вот как-то так: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.
... |
|||
:
Нравится:
Не нравится:
|
|||
25.11.2019, 09:33 |
|
Почему не используется индекс из двух полей при выборке только по первому полю?
|
|||
---|---|---|---|
#18+
Maxim Boguk, Могу попробовать изменить cost на cpu. Наверное после надо убрать это: alter table respondents alter project_id set STATISTICS 10000; alter table respondents alter project_id set (n_distinct = 10000); и проверить исходный запрос? т.к. с этими вот подсказками он и так индекс сейчас использует ... |
|||
:
Нравится:
Не нравится:
|
|||
25.11.2019, 09:35 |
|
|
start [/forum/topic.php?fid=53&msg=39893116&tid=1994921]: |
0ms |
get settings: |
9ms |
get forum list: |
15ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
36ms |
get topic data: |
11ms |
get forum data: |
3ms |
get page messages: |
66ms |
get tp. blocked users: |
1ms |
others: | 15ms |
total: | 164ms |
0 / 0 |