2012-06-26 2 views
2

PHP에서 그래프의 데이터를 생성하려고하는데, 매 시간마다 세분화 된 특정 시간대에 mysql 테이블의 레코드 양을 표시합니다. 각 레코드에는 유닉스 타임 스탬프가 있습니다.mysql 테이블에서 시간별 통계를 표시하는 방법

예를 들어 오늘의 통계를 표시하고 싶다고합시다. 아래의 코드는 "작동"하지만 실행 한 후에 내가 한 일을 보면 작동하는 끔찍한 횡설수설입니다. 수백만 개의 색인 된 레코드가있는 테이블에서이 작업을 실행하면 느려집니다.

지금은 24 시간에 도달 할 때까지 매 시간마다 쿼리를 수행합니다. 문제는 최대 10 개의 다른 테이블에서 동시에 데이터를 가져 오려고하는 것입니다. 즉, 좋지 않은 모든 페이지로드시 최대 240 개의 쿼리를 실행할 수 있습니다.

$c = '0'; 
$h = '1'; 
while($h < 25){ 
    $hr_start = 3600 * $c; 
    $hr_stop = 3600 * $h; 
    $query = "SELECT `reason`,`timestamp` 
    FROM `c_blacklist` 
    WHERE `timestamp` > '".strtotime('today')."' + ".$hr_start." AND `timestamp` < '".strtotime('today')."' + ".$hr_stop." AND `reason` = 'hardbounce'"; 
    $result = mysql_query($query) or die(mysql_error()); 
    $hardbounce_count = mysql_num_rows($result); 
    $dataset5[] = array($h,$hardbounce_count); 
    $h++; 
    $c++; 
} 

나는이 작업을 수행 할 수있는 더 좋은 방법이 알고 난 그냥에 많은 정보를 찾을 수 없어. 1 개의 쿼리를 실행 한 다음 PHP로 시간을 분할하고 데이터 집합에 삽입 할 수 있습니까? 나는 너무 혼란스럽고 어떤 도움을 주셔서 감사합니다. 감사.

+0

GROUP BY HOUR (FROM_UNIXTIME (unixtime)) WHERE date = DATE (FROM_UNIXTIME (unixtime)) 할 수 있습니까? – Kermit

+0

'c_blacklist'에서'timestamp' 란 이름의 컬럼의 데이터 타입은 무엇입니까? 그것은'TIMESTAMP'입니까, 아니면'DATETIME'입니까? timestamp 열의 WHERE 절이 최적보다 적을 수 있습니다. – spencer7593

답변

0
$query = "SELECT `reason`,`timestamp`,FROM_UNIXTIME(timestamp, '%H') as Hour 
FROM `c_blacklist` 
WHERE `timestamp` > ('".strtotime('today')."' + ".$hr_start.") AND (`timestamp` < '".strtotime('today')."' + ".$hr_stop.") AND `reason` = 'hardbounce' 
GROUP BY FROM_UNIXTIME(timestamp, '%H')"; 

추가 된 일부()의 동작 보호의 주문하지만, FROM_UNIXTIME 추가하면 시간 가정 타임 스탬프 인 시대/유닉스 타임 스탬프를 줄 것이다 ('%의 H', 타임 스탬프).

3

전화를 걸면 마지막 24 시간의 데이터를 제공하는 일종의 "보고 쿼리"를 만들 수 있습니다.

첫 번째 단계는 숫자 1-24 (논리에 따라 0-23)를 포함하는 24 개의 행으로 참조 테이블을 만드는 것입니다. 나는이 표를 hours라고 부를 것이다. 이 참조 표를 사용하면 주어진 시간 내에 활동이 없으면 0 카운트를 얻습니다. 이는 타임 스탬프에서 GROUP BY 만하는 접근 방식과 다릅니다.

나서, 이 테이블 가입 왼쪽 TIMEDIFFHOUR 및 기능들의 조합을 사용한다. 이런 식으로 뭔가 (테스트되지 않은하지만 당신은 아이디어를 얻을) : 지난 24 시간에서 각각 "이유"의 수

SELECT 
    COUNT(c_blacklist.reason) as num_reasons, 
    hours.hour as hour 
FROM hours 
LEFT JOIN c_blacklist 
    ON HOUR(TIMEDIFF(now(), c_blacklist.timestamp)) = hours.hour 
GROUP BY hours.hour 

이 출력됩니다 24 행. 약간의 시간 소인을 추가 할 수 있습니다.

+0

나는이 개념에 동의하고 싶다. Google은 80,000 개의 다른 학교에서 수백만 개의 동영상에 대한 모든 동영상 이벤트 (재생/일시 중지/정지/시작)를 기록하므로 로그를 가져 와서 사용자가보고 싶은 것을 최적화하는 기록 요약 및보기를 만드는 밤샘 프로세스가 있습니다. – GDP

+0

+1 데이터베이스에서 모든 행을 검색하고 클라이언트 측에서 계산하는 것보다 데이터베이스가 COUNT를 리턴하게하는 것이 훨씬 빠를 것입니다. – spencer7593

+0

+1. 이것이 가능한 접근법입니다. 한 가지 우려 사항은 c_blacklist에 큰 날짜 범위에 걸쳐 많은 수의 행이있는 경우 성능입니다. 나는이 쿼리로 MySQL이 timestamp 컬럼의 인덱스를 사용할 수 있다고 믿지 않는다. – spencer7593

1

시간 소인의 시간 값으로 그룹화하십시오.

SELECT 
    date_format(`timestamp`,'%H') day_hour, 
    count(*) count 
FROM 
    `c_blacklist` 
WHERE 
    `timestamp` between $start and $end 
    and `reason` = 'hardbounce' 
GROUP BY 
    date_format(`timestamp`,'%H') 
ORDER BY 
    1; 

$result = mysql_query($query) or die(mysql_error()); 
foreach($row = mysql_fetch_array($result)) { 
    $dataset5[] = array($row['day_hour'],$row['count']) 
} 
2

모든 세부 행을 가져오고 클라이언트 측에서 카운트하는 것이 아니라 데이터베이스가 카운트를 반환하도록하는 것이 훨씬 빠릅니다.

그리고 하나의 쿼리에서 전체 24 시간 동안 카운트를 가져올 수 있습니다. 개별 카운트를 얻기 위해 데이터베이스를 24 라운드 왕복하는 것보다 훨씬 효율적입니다.

인덱스가 c_blacklist(timestamp) 이상이거나 c_blacklist(timestamp,reason)의 커버 인덱스 인 경우 쿼리 성능이 향상 될 가능성이 높습니다.

TIMESTAMP의 열이있는 경우 간단한 계산을 수행하여 "시간"을 얻고 각 "시간"을 계산할 수 있습니다.

SELECT FROM_UNIXTIME((UNIX_TIMESTAMP(cb.`timestamp`) DIV 3600) * 3600) AS `cb_hour` 
    , COUNT(1) AS cb_count 
    FROM `c_blacklist` cb 
WHERE cb.`timestamp` >= DATE_ADD('2012-06-26 18:00',INTERVAL -1 DAY) 
    AND cb.`timestamp` < '2012-06-26 18:00' 
    AND cb.`reason` = 'hardbounce' 
GROUP BY FROM_UNIXTIME((UNIX_TIMESTAMP(cb.`timestamp`) DIV 3600) * 3600) 
ORDER BY FROM_UNIXTIME((UNIX_TIMESTAMP(cb.`timestamp`) DIV 3600) * 3600) 

타임 스탬프 열이 데이터 형식 DATETIME의 경우, 시간을 얻기 위해 다른 표현을 사용하는 것이 더 빠를 수 있습니다

SELECT DATE_FORMAT(cb.`timestamp`,'%Y-%m-%d %H:00:00') AS `cb_hour` 
    , COUNT(1) AS cb_count 
    FROM `c_blacklist` cb 
WHERE cb.`timestamp` >= DATE_ADD('2012-06-26 18:00',INTERVAL -1 DAY) 
    AND cb.`timestamp` < '2012-06-26 18:00' 
GROUP BY DATE_FORMAT(cb.`timestamp`,'%Y-%m-%d %H:00:00') 
ORDER BY DATE_FORMAT(cb.`timestamp`,'%Y-%m-%d %H:00:00') 

이 쿼리가있다 "격차"가됩니다 계산할 행이 없습니다. 즉, 0의 수를 리턴하지 않습니다.

"시간"에 대한 각 값을 반환하는 행 원본을 제공 한 다음 결과 집합을 사용하여 왼쪽 조인을 수행하면 해결할 수 있습니다. 다음 명령문에서 h로 별명이 지정된 부속 조회는 시간당 하나씩 24 행을 리턴합니다. 우리는 "결과"쿼리 (위의)에 대한 왼쪽 조인의 구동 행 소스로이를 사용합니다. 우리가 일치하지 않는 곳이라면, 카운트에 대해 NULL을 얻습니다. 그리고 우리는 NULL을 0으로 간단하게 함수 호출로 대체 할 수 있습니다.

SELECT h.hour AS cb_hour 
    , IFNULL(c.cb_count,0) AS cb_count 
    FROM (SELECT DATE_ADD('2012-06-26 18:00',INTERVAL -1*d.i HOUR) AS `hour` 
      FROM (SELECT 00 AS i UNION ALL SELECT 01 UNION ALL SELECT 02 UNION ALL SELECT 03 
       UNION ALL SELECT 04 UNION ALL SELECT 05 UNION ALL SELECT 06 UNION ALL SELECT 07 
       UNION ALL SELECT 08 UNION ALL SELECT 09 UNION ALL SELECT 10 UNION ALL SELECT 11 
       UNION ALL SELECT 12 UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15 
       UNION ALL SELECT 16 UNION ALL SELECT 17 UNION ALL SELECT 18 UNION ALL SELECT 19 
       UNION ALL SELECT 20 UNION ALL SELECT 21 UNION ALL SELECT 22 UNION ALL SELECT 23 
       ORDER BY 1 DESC 
       ) d 
     ) h 
    LEFT 
    JOIN (SELECT FROM_UNIXTIME((UNIX_TIMESTAMP(cb.`timestamp`) DIV 3600) * 3600) AS `cb_hour` 
      , COUNT(1) AS cb_count 
      FROM `c_blacklist` cb 
     WHERE cb.`timestamp` >= DATE_ADD('2012-06-26 18:00',INTERVAL -1 DAY) 
      AND cb.`timestamp` < '2012-06-26 18:00' 
      AND cb.`reason` = 'hardbounce' 
     GROUP BY FROM_UNIXTIME((UNIX_TIMESTAMP(cb.`timestamp`) DIV 3600) * 3600) 
     ORDER BY FROM_UNIXTIME((UNIX_TIMESTAMP(cb.`timestamp`) DIV 3600) * 3600) 
     ) c 
    ON c.cb_hour = h.hour 
ORDER BY h.hour 

허용 된 쿼리 텍스트는 현재 가지고있는 것보다 훨씬 많습니다.

내 코드로 가져 오려면 날짜 리터럴의 세 번을 '% s'으로 바꾸고 sprintf를 사용하여 세 번 발생 된 날짜 문자열을 형식이 지정된 날짜 문자열로 바꿉니다. (세 개의 모든 항목에 대해 동일한 값이 전달됩니다.)

관련 문제