Mysql запрос диапазона дат медленный - PullRequest
0 голосов
/ 10 июля 2020

У меня есть 2 mysql таблицы spot_times - 10k строк и visit_times - 5,3 миллиона строк .

Я пытаюсь написать запрос, который может присоединиться spot_times.spot_date на visit_times.visit_date на основе 10-минутного окна.

Оба поля даты индексируются и тип столбца datetime.

Я написал следующее sql, выполнение которого занимает несколько часов.

    Select spot_date, count(visit_date) total_visits
      From spot_times st 
      Left 
      Join visit_times v 
        on v.visit_date between st.spot_date and st.spot_date + interval 10 minute

    group by 1;

На выполнение этого запроса уходит часы.

Похоже, что мой план объяснения не использует индексы.

План объяснения

Пожалуйста, помогите.

Ответы [ 2 ]

0 голосов
/ 20 июля 2020

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

Я начал с добавления столбца auto_increment visit_id в таблицу visits_times, упорядоченную по полю visit_date.

Идея состоит в том, чтобы получить visit_id, ближайшее к st.spot_date и st.spot_date + interval 10 minute. Затем вычтите visit_id, которое должно быть общим количеством посещений между диапазоном.

Создана функция для возврата visit_id для даты и интервала. Функция использует индекс visit_date и выполняет цикл до тех пор, пока не найдет запись, добавляющую секунду на каждые l oop.

DELIMITER //

DROP function IF EXISTS `spot_time_function` //

CREATE  function `spot_time_function`( p_datetime datetime, p_time int)
returns int
BEGIN
        
declare v_id  int ;              
declare z int;         
        
set z = 0;   
    
    time_loop:  LOOP
    
    select visit_id into v_id from visit_times where visit_date = p_datetime + interval p_time minute + interval z second limit 1;
    
            IF  v_id is not null THEN 
                LEAVE  time_loop;
            END  IF;
                
            SET  z = z + 1;
        
    END LOOP;     
    
return v_id;
    
END //

DELIMITER ;

Итак, окончательный запрос выглядит так.

Select 
spot_date, 
spot_time_function(spot_date,10) - spot_time_function(spot_date,0) as total_visit 
From spot_times;

Вышеуказанный запрос выполняется за 0,110 se c.

0 голосов
/ 13 июля 2020

Запросы диапазона, как известно, трудно добиться полезной производительности индекса для больших наборов данных.

Вы можете получить некоторую выгоду от секционирования visit_times по диапазону дат: https://dev.mysql.com/doc/refman/8.0/en/partitioning-range.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...