Postgresql Query выполняется медленно

У меня есть запрос PostgreSql следующим образом:

SELECT DISTINCT ON (reference) reference, reference_url 
FROM vehicles v 
WHERE NOT EXISTS 
    (select reference 
     from daily_run_vehicle rv 
     WHERE ((
           handled = False 
           AND retries >= 5 ) 
           OR rv.timestamp::timestamp::date = now()::date)  
     AND v.reference=reference);

Где таблица vehicles содержит около 400 тысяч записей, а таблица daily_run_vehicle содержит около 50 миллионов записей.

Таким образом, мне нужны все транспортные средства, где это транспортное средство не добавлено в daily_run_vehicle сегодня или где обработанный столбец имеет значение False И повторяет попытки column is >= 5.

Но проблема в том, что запрос выполняется слишком долго.

Есть ли способ написать его лучше, чтобы он выполнялся быстрее?


person Boky    schedule 06.03.2019    source источник
comment
Пожалуйста, отредактируйте свой вопрос и добавьте операторы create table для рассматриваемых таблиц (включая все индексы) и план выполнения, созданный с помощью explain (analyze, buffers) (не просто объяснение) как форматированный текст. Без скриншотов, пожалуйста. Вы также можете загрузить план на explain.depesz.com.   -  person a_horse_with_no_name    schedule 06.03.2019
comment
Почему disctinct on ()? Без заказа это не имеет смысла. Также: почему вы присваиваете временную метку временной метке?   -  person a_horse_with_no_name    schedule 06.03.2019
comment
@a_horse_with_no_name У меня есть другие записи с той же ссылкой. А вместо timestamp::timestamp::date можно использовать timestamp::date?   -  person Boky    schedule 06.03.2019
comment
Если timestamp является timestamp, то нет причин приводить его к timestamp   -  person a_horse_with_no_name    schedule 06.03.2019


Ответы (2)


У меня есть теория, что это может быть связано с вызовом функции now() миллионы раз. Вы можете проверить, выполнив этот запрос вместо этого

SELECT DISTINCT ON (reference) reference, reference_url 
FROM vehicles v 
WHERE NOT EXISTS 
    (select reference 
     from daily_run_vehicle rv 
     WHERE ((
           handled = False 
           AND retries >= 5 ) 
           OR rv.timestamp::timestamp::date = '2019-03-06')  
     AND v.reference=reference);

Если производительность улучшится, вам нужно будет установить сегодняшнюю дату в переменную и использовать переменную в запросе, чтобы сделать только 1 вызов сейчас. С другой стороны, если вы используете EXISTS, традиция состоит в том, чтобы иметь SELECT 1 FROM ... вам не нужны значения, просто есть ли хотя бы одно или нет.

person Eponyme Web    schedule 06.03.2019

Хм. Я думаю:

SELECT DISTINCT ON (v.reference) v.reference, v.reference_url 
FROM vehicles v 
WHERE NOT EXISTS (select 1 
                  from daily_run_vehicle rv 
                  where rv.reference = v.reference and
                        rv.handled = False and
                        rv.retries >= 5
                 ) and
      NOT EXISTS (select 1 
                  from daily_run_vehicle rv 
                  where rv.reference = v.reference and
                        rv.timestamp >= current_date::timestamp and
                        rv.timestamp >= (current_date + interval '1 day'::timestamp 
                 )
ORDER BY v.reference;

Для этого запроса вам нужны индексы:

  • daily_run_vehicle(reference, handled, retries)
  • daily_run_vehicle(reference, timestamp)
  • reference_url(reference, reference_url)
person Gordon Linoff    schedule 06.03.2019