2012-06-18 2 views
6

entry_time과 value라는 두 개의 열이있는 데이터베이스 테이블이 있다고 가정 해 보겠습니다. entry_time은 타임 스탬프이며 value는 다른 데이터 유형이 될 수 있습니다. 레코드는 비교적 일관되고 대략 x 분 간격으로 입력됩니다. 그러나 많은 시간 동안 엔트리가 만들어지지 않아서 데이터에 '갭'이 생길 수 있습니다.MySQL에서 시계열 데이터의 간격을 찾는 방법은 무엇입니까?

효율성 측면에서 쿼리를 사용하여 적어도 Y (신구도) 시간 간격의 이러한 간격을 찾는 가장 좋은 방법은 무엇입니까?

+0

어떻게 간격을 정의합니까? 입력 사이에 시간이 얼마나 걸릴지에 대해 엄격한 제한을두고 있습니까? –

+0

변수 Y입니다. 지정하지 않았습니다. – TheDog

답변

15

시작하려면 테이블에 시간별 항목 수를 요약 해 보겠습니다.

이제 6 분마다 (10 시간 씩) 로그를 남기면 모든 샘플 카운트 값은 10이되어야합니다. 이 표현식은 CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME)입니다. 털이 보입니다.하지만 시간 소인을 분과 초를 제로로하여 발생하는 시간으로 간단히 자릅니다.

이것은 비교적 효율적이며 시작하게됩니다. entry_time 열에 인덱스를 추가하고 여기에 표시된 것처럼 어제의 샘플을 쿼리로 제한 할 수 있다면 매우 효율적입니다.

SELECT CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME) hour, 
     COUNT(*) samplecount 
    FROM table 
WHERE entry_time >= CURRENT_DATE - INTERVAL 1 DAY 
    AND entry_time < CURRENT_DATE 
GROUP BY CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME) 

그러나 누락 된 샘플이있는 전체 시간을 감지하는 것은 그리 좋지 않습니다. 샘플링에서 지터에 약간 민감합니다. 즉, 시간의 가장 빠른 샘플이 때로는 0.5 초 (10:59:30)이고 때로는 0.5 초 늦은 시간 (11:00:30) 인 경우 시간별 요약 카운트가 해제됩니다. 따라서이 시간 요약 작업 (또는 요일 요약 또는 분 요약 등)은 방탄하지 않습니다.

물건을 완벽하게 얻으려면 자체 조인 쿼리가 필요합니다. 그것은 좀 더 털이 있고 거의 효율적이지 않습니다.

번호가 매겨진 샘플을 사용하여 가상 테이블 (하위 쿼리)을 만들어 보겠습니다. (이것은 MySQL은 고통입니다. 다른 고가의 DBMS는 쉽게 상관없이합니다.)

SELECT @sample:[email protected]+1 AS entry_num, c.entry_time, c.value 
    FROM (
     SELECT entry_time, value 
     FROM table 
     ORDER BY entry_time 
    ) C, 
    (SELECT @sample:=0) s 

이 작은 가상 테이블은 entry_num, entry_time, 값을 제공합니다.

다음 단계로 넘어갑니다.

SELECT one.entry_num, one.entry_time, one.value, 
     TIMEDIFF(two.value, one.value) interval 
    FROM (
    /* virtual table */ 
) ONE 
    JOIN (
    /* same virtual table */ 
) TWO ON (TWO.entry_num - 1 = ONE.entry_num) 

이것은 다음 두 개의 테이블을 JOIN의 ON 절에 의해 제어되는 단일 항목으로 서로 빗나가게합니다.

마지막으로 임계 값보다 큰 interval을 사용하여이 테이블의 값을 선택합니다. 누락 된 값 바로 앞에 샘플의 시간이 있습니다.

전체 자체 조인 쿼리가 여기에 해당합니다. 나는 그것이 털이있는 사람이라고 말했다. 당신은 큰 테이블에 생산이 작업을 수행해야하는 경우

SELECT one.entry_num, one.entry_time, one.value, 
     TIMEDIFF(two.value, one.value) interval 
    FROM (
    SELECT @sample:[email protected]+1 AS entry_num, c.entry_time, c.value 
     FROM (
      SELECT entry_time, value 
      FROM table 
      ORDER BY entry_time 
    ) C, 
     (SELECT @sample:=0) s 
) ONE 
    JOIN (
    SELECT @sample2:[email protected]+1 AS entry_num, c.entry_time, c.value 
     FROM (
      SELECT entry_time, value 
      FROM table 
      ORDER BY entry_time 
    ) C, 
     (SELECT @sample2:=0) s 
) TWO ON (TWO.entry_num - 1 = ONE.entry_num) 

당신은 당신의 데이터의 하위 집합을 위해 그것을 할 수 있습니다. 예를 들어, 지난 2 일간의 샘플을 매일 할 수 있습니다. 이것은 매우 효율적일 것이며, 자정에 누락 된 샘플을 간과하지 않았 음을 확인할 것입니다. 이렇게하기 위해 당신의 작은 rownumbered 가상 테이블은 이렇게 보일 것입니다.

SELECT @sample:[email protected]+1 AS entry_num, c.entry_time, c.value 
    FROM (
     SELECT entry_time, value 
     FROM table 
     ORDER BY entry_time 
     WHERE entry_time >= CURRENT_DATE - INTERVAL 2 DAY 
      AND entry_time < CURRENT_DATE /*yesterday but not today*/ 
    ) C, 
    (SELECT @sample:=0) s 
+0

정확히 @sample : = @ sample + 1이 무엇을하는지 혼란 스럽지만,이 솔루션에 대해 대단히 감사합니다. – TheDog

+0

이'@ sample' 변수는 행 번호를 추적합니다. '(SELECT @sample : = 0)'으로 초기화되고 테이블의 각 행마다 증가합니다. Oracle에 대해 지불 할 수만 달러를 가지고 있다면, ROWNUM이라고 말할 수 있습니다. 그러나 이것은 MySQL을 똑같이 해킹하는 것입니다. 신비, 응? –

+0

+1 단계별 설명 – kirugan

1

매우 효율적인 방법은 커서를 사용하는 저장 프로 시저를 사용하는 것입니다.나는 이것이 다른 대답보다 더 간단하고 효율적이라고 생각한다.

이 절차는 커서를 생성하고 검사중인 datetime 레코드를 통해 커서를 반복합니다. 당신이 지정한 것보다 더 큰 차이가 있다면, 그것은 갭의 시작과 끝을 테이블에 기록 할 것입니다.

CREATE PROCEDURE findgaps() 
    BEGIN  
    DECLARE done INT DEFAULT FALSE; 
    DECLARE a,b DATETIME; 
    DECLARE cur CURSOR FOR SELECT dateTimeCol FROM targetTable 
          ORDER BY dateTimeCol ASC; 
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;  
    OPEN cur;  
    FETCH cur INTO a;  
    read_loop: LOOP 
     SET b = a; 
     FETCH cur INTO a; 
     IF done THEN 
      LEAVE read_loop; 
     END IF;  
     IF DATEDIFF(a,b) > [range you specify] THEN 
      INSERT INTO tmp_table (gap_begin, gap_end) 
      VALUES (a,b); 
     END IF; 
    END LOOP;   
    CLOSE cur;  
    END; 

이 경우 'tmp_table'이 있다고 가정합니다. 프로 시저에서 이것을 TEMPORARY 테이블로 쉽게 정의 할 수 있지만이 예제에서는 생략했습니다.

관련 문제