PostgreSQL использует другой индекс для одного и того же запроса - PullRequest
0 голосов
/ 22 ноября 2018

У меня есть SQL-запрос, который использует внутреннее соединение двух таблиц и фильтрует данные по нескольким параметрам.Исходя из плана запроса, для разных значений параметров запроса (например, для другого диапазона дат) Postgres использует другой индекс.

Мне известно о том, что Postgres определяет, должен ли индекс использоваться или нет, в зависимости от числа или строк в наборе результатов.Но почему Postgres предпочитает использовать разные индексы для одного и того же запроса.Время запроса варьируется в 10 раз между двумя случаями.Как я могу оптимизировать запрос?Поскольку Postgres не позволяет пользователю определять индекс, который будет использоваться в запросе.

Редактировать:

explain (analyze, buffers, verbose) SELECT COUNT(*) FROM "bookings" INNER JOIN "hotels" ON "hotels"."id" = "bookings"."hotel_id" WHERE "bookings"."hotel_id" = 37016 AND (bookings.status in (0,1,2,3,4,5,6,7,9,10,11,12)) AND (bookings.source in (0,1,2,3,4,5,6,7,8,9,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,59,60,61,62,63,64,65,66,67,68,69,70) or bookings.status in (0,1,2,3,4,5,6,7,8,9,10,11,13)) AND (
bookings.source in (4,66,65)
OR
date(timezone('+05:30',bookings.created_at))>checkin
OR
(
( date(timezone('+05:30',bookings.created_at))=checkin
and
extract (epoch from COALESCE(cancellation_time,NOW())-bookings.created_at)>600
)
OR
( date(timezone('+05:30',bookings.created_at))<checkin
and
extract (epoch from COALESCE(cancellation_time,NOW())-bookings.created_at)>600
and
(
extract (epoch from ((bookings.checkin||' '||hotels.checkin_time)::timestamp -COALESCE(cancellation_time,bookings.checkin))) < extract(epoch from '16 hours'::interval)
OR
(DATE(bookings.checkout)-DATE(bookings.checkin))*(COALESCE(bookings.oyo_rooms,0)+COALESCE(bookings.owner_rooms,0)) > 3
)
)
)
) AND (bookings.checkin >= '2018-11-21') AND (bookings.checkin <= '2019-05-19') AND "bookings"."hotel_id" = '37016' AND "bookings"."status" IN (0, 1, 2, 3, 12);

QueryPlan: https://explain.depesz.com/s/SPeb

explain (analyze, buffers, verbose) SELECT COUNT(*) FROM "bookings" INNER JOIN "hotels" ON "hotels"."id" = 37016 WHERE "bookings"."hotel_id" = 37016 AND (bookings.status in (0,1,2,3,4,5,6,7,9,10,11,12)) AND (bookings.source in (0,1,2,3,4,5,6,7,8,9,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,59,60,61,62,63,64,65,66,67,68,69,70) or bookings.status in (0,1,2,3,4,5,6,7,8,9,10,11,13)) AND (
bookings.source in (4,66,65)
OR
date(timezone('+05:30',bookings.created_at))>checkin
OR
(
( date(timezone('+05:30',bookings.created_at))=checkin
and
extract (epoch from COALESCE(cancellation_time,now())-bookings.created_at)>600
)
OR
( date(timezone('+05:30',bookings.created_at))<checkin
and
extract (epoch from COALESCE(cancellation_time,now())-bookings.created_at)>600
and
(extract (epoch from ((bookings.checkin||' '||hotels.checkin_time)::timestamp -COALESCE(cancellation_time,bookings.checkin))) < extract(epoch from '16 hours'::interval)
OR
(DATE(bookings.checkout)-DATE(bookings.checkin))*(COALESCE(bookings.oyo_rooms,0)+COALESCE(bookings.owner_rooms,0)) > 3
)
)
)
) AND (bookings.checkin >= '2018-11-22') AND (bookings.checkin <= '2019-05-19') AND "bookings"."hotel_id" = '37016' AND "bookings"."status" IN (0,1,2,3,4,12);

QueryPlan: https://explain.depesz.com/s/DWD

1 Ответ

0 голосов
/ 18 декабря 2018

Наконец-то нашли решение этой проблемы.Я запрашиваю более 10 возможных значений столбца (в данном случае status ).Если я разбиваю этот запрос на несколько подзапросов, каждый из которых запрашивает только одно значение состояния, и агрегирую результат, используя объединение всех, тогда выполняемый план запроса использует оптимизированный индекс для каждого подзапроса.

Результаты: время запроса уменьшилось наЭто изменение в 10 раз.

Возможное объяснение этого поведения: планировщик запросов выбирает меньшее количество строк для каждого подзапроса и использует оптимизированный индекс в этом случае.Я не уверен, если это правильное объяснение.

...