2 почти идентичных выбора в одной и той же таблице БД занимают совершенно разное время для выполнения

на Рождество у меня есть один вопрос, с которым я действительно изо всех сил пытаюсь найти подсказки о том, как с ним справиться.

У меня есть одна БД отчетов, она заполнена данными из спутниковых баз данных на многих небольших машинах. Выборки данных выполняются одинаково, каждые 20 минут для каждой спутниковой БД. Они используют все тот же сценарий. Однако они находятся на разных установках, разбросанных по всей стране.

Теперь у меня есть один SELECT, используемый отчетами Pentaho, которые выполняются в той же таблице БД в этой БД отчетов. и в то время как выполнение одного SELECT занимает миллисекунды, другое занимает буквально часы. Они оба выполняются над одной и той же таблицей, в одной БД, работающей на одном и том же оборудовании.

Быстрый:

SELECT
 res.ticket_id,
 res.entry_zone,
 res.entry_time,
 res.exit_time,
 res.parking_time,
 res.cost,
 co.org_name,
 cu.firstname,
 cu.surname,
 a.name AS article_name,
 res.car_id 
FROM (SELECT
 lh.ticket_id,
 z.name AS entry_zone,
 lh.park_entered AS entry_time,
 lh.park_leaved AS exit_time,
 interval_to_hourminsec(lh.park_leaved - lh.park_entered) AS parking_time,
 lh.cost,
 lh.article_id,
 sa.contrib_user_id,
 fpl.car_id
 FROM longterm_history lh, zones z, sold_articles sa, flexcore_passing_log fpl
 WHERE lh.park_leaved BETWEEN  '2017-12-18 00:00' AND  '2017-12-19 23:59'
 AND sa.ticket_id = lh.ticket_id
 AND lh.entry_zone = z.zone_number
 AND lh.passlog_id = fpl.id
 AND lh.park_uuid = 100068
 AND z.park_uuid = 100068
 AND sa.park_uuid = 100068
 AND fpl.park_uuid = 100068
 AND lh.entry_zone = 1
) AS res 
LEFT OUTER JOIN articles a ON res.article_id = a.article_id AND a.park_uuid = 100068 
LEFT OUTER JOIN cont_users cu ON res.contrib_user_id = cu.id AND cu.park_uuid = 100068 
LEFT OUTER JOIN cont_orgs co ON cu.org_id = co.id AND co.park_uuid = 100068 
ORDER BY res.exit_time ASC

Медленно:

SELECT
 res.ticket_id,
 res.entry_zone,
 res.entry_time,
 res.exit_time,
 res.parking_time,
 res.cost,
 co.org_name,
 cu.firstname,
 cu.surname,
 a.name AS article_name,
 res.car_id 
FROM (SELECT
 lh.ticket_id,
 z.name AS entry_zone,
 lh.park_entered AS entry_time,
 lh.park_leaved AS exit_time,
 interval_to_hourminsec(lh.park_leaved - lh.park_entered) AS parking_time,
 lh.cost,
 lh.article_id,
 sa.contrib_user_id,
 fpl.car_id
 FROM longterm_history lh, zones z, sold_articles sa, flexcore_passing_log fpl
 WHERE lh.park_leaved BETWEEN  '2017-12-18 00:00' AND  '2017-12-19 23:59'
 AND sa.ticket_id = lh.ticket_id
 AND lh.entry_zone = z.zone_number
 AND lh.passlog_id = fpl.id
 AND lh.park_uuid = 100146
 AND z.park_uuid = 100146
 AND sa.park_uuid = 100146
 AND fpl.park_uuid = 100146
 AND lh.entry_zone = 1
) AS res 
LEFT OUTER JOIN articles a ON res.article_id = a.article_id AND a.park_uuid = 100146 
LEFT OUTER JOIN cont_users cu ON res.contrib_user_id = cu.id AND cu.park_uuid = 100146 
LEFT OUTER JOIN cont_orgs co ON cu.org_id = co.id AND co.park_uuid = 100146 
ORDER BY res.exit_time ASC

как узнать где проблема, из-за чего выполняется второй SELECT часов?

Я использую postgres SQL, версия сервера 9.6.3. Данные извлекаются в базы данных с помощью интеграции данных Pentaho.


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

После запуска обоих запросов через EXPLAIN (ANALYZE, BUFFERS) самая большая существенная разница в этой части:

                                           ->  Bitmap Index Scan on longterm_history_park_uuid_idx  (cost=0.00..7609.82 rows=352718 width=0) (actual time=492.753..492.753 rows=354537 loops=1)
                                                 Index Cond: (park_uuid = 100068)
                                                 Buffers: shared read=1238

                                           ->  Bitmap Index Scan on longterm_history_park_uuid_idx  (cost=0.00..453.11 rows=20890 width=0) (actual time=4.680..4.680 rows=40021 loops=466475)
                                                 Index Cond: (park_uuid = 100146)
                                                 Buffers: shared hit=65306361 read=139

и кажется, что второй SELECT медленнее loops=466475 вместо loops=1 dne первым SELECT. Но я понятия не имею, что это значит и как это исправить.


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

У меня есть инструмент для обмена планами в Интернете, вот ссылки:

Быстрый запрос: https://explain.depesz.com/s/oYQLB

Медленный запрос: https://explain.depesz.com/s/uOtf

Медленный запрос выполнялся быстро, пока выборка была отключена: https://explain.depesz.com/s/4h4F< /а>


person rRr    schedule 22.12.2017    source источник
comment
stackoverflow.com/help/mcve   -  person jarlh    schedule 22.12.2017
comment
Пожалуйста, опубликуйте EXPLAIN (ANALYZE, BUFFERS) вывод для обоих запросов. Также было бы хорошо, если бы вы сказали нам, в чем разница между запросами, вместо того, чтобы позволить нам искать.   -  person Laurenz Albe    schedule 22.12.2017
comment
В обоих запросах нет разницы, разница только в значении park_uuid, даты и другие параметры одинаковы для обоих. Я знаю, что у вас не так много возможностей помочь без доступа к полному набору данных. Я больше похож на то, чтобы попросить совета, как проанализировать проблему.   -  person rRr    schedule 22.12.2017
comment
Может ли это быть проблемой сниффинга параметров?   -  person HoneyBadger    schedule 22.12.2017
comment
Если единственная разница заключается в значении park_uuid, то для начала я бы провел подсчет строк в каждой таблице для каждого из искомых вами park_uuid. Я бы также попробовал выполнить запрос через инструмент командной строки psql, чтобы исключить все, что может делать Pentaho. Может ты это уже сделал? И я думаю, что оптимизатор запросов справится с этим, но я бы поместил буквальное значение один раз и использовал соединения, чтобы сопоставить его с другими таблицами, чтобы помочь оптимизатору выполнить свою работу.   -  person Ron Ballard    schedule 22.12.2017
comment
@LaurenzAlbe Я боюсь, что результаты слишком велики для поста здесь. Могу ли я поделиться ими с вами другим способом? Я пытался получить информацию о них самостоятельно, но это кажется слишком грязным ... возможно, нужно немного привыкнуть к этому.   -  person rRr    schedule 03.01.2018
comment
@LaurenzAlbe Я нашел способ поделиться планами в Интернете, поэтому добавил ссылки в исходный пост.   -  person rRr    schedule 04.01.2018
comment
Отлично. И как только вы изучили планы, вы сами нашли правильный ответ - статистика таблицы была отключена.   -  person Laurenz Albe    schedule 05.01.2018


Ответы (1)


Проблема была решена.

Узнав, как читать EXPLAIN ANALYZE с помощью множества веб-инструментов, чтобы графически показать это, я заметил, что второй (МЕДЛЕННЫЙ) выбор выполняет большое количество циклов, и оптимизатор ожидает, что будет возвращено меньше строк, чем он действительно возвращает.

Это было признаком неправильных данных, на которых основаны расчеты оптимизаторов. Чтобы решить эту проблему, я запустил VACUUM ANALYZE для всей БД.

В результате значительно улучшилась производительность, время выполнения запроса сократилось с 4265437,080 мс до 547,202 мс.

person rRr    schedule 04.01.2018