2009-07-07 5 views
0

쿼리 속도를 높이는 방법과 동시에 date/mktime 함수를 호출하는 데 필요한 오버 헤드를 최소화하는 방법에 대한 최적의 방법에 대한 조언을 찾고 있습니다.다른 반전으로 그룹화해야하는 쿼리에서로드를 최소화하는 방법은 무엇입니까?

CREATE TABLE my_table(
    id INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT, 
    important_data INTEGER, 
    date INTEGER); 

는 사용자가 1을 표시하도록 선택할 수 있습니다) 두 날짜 사이의 모든 항목 :

SELECT * FROM my_table 
    WHERE date >= ? AND date <= ? 
    ORDER BY date DESC; 

출력 :

10-21-2009 12:12:12, 10002 
10-21-2009 14:12:12, 15002 
10-22-2009 14:05:01, 20030 
10-23-2009 15:23:35, 300 
.... 
나는 다음과 같은 테이블 레이아웃을 처리하고있어 문제를 사소하게하려면

이 경우 개선 할 점이 많지 않다고 생각합니다.

2) 하루 요약한다/그룹 출력, 주, 월, 년 : 월별로

SELECT COUNT(*) AS count, SUM(important_data) AS important_data 
    FROM my_table 
    WHERE date >= ? AND date <= ? 
    ORDER BY date DESC; 

예 출력 :

10-2009, 100002 
11-2009, 200030 
12-2009, 3000 
01-2010, 0 /* <- very important to show empty dates, with no entries in the table! */ 
.... 

나는 현재를 실행하는거야) 옵션 2를 달성하기 다음과 같은 mktime/date를위한 매우 비용이 많이 드는 for-loop :

for(...){ /* example for group by day */ 
    $span_from = (int)mktime(0, 0, 0, date("m", $time_min), date("d", $time_min)+$i, date("Y", $time_min)); 
    $span_to = (int)mktime(0, 0, 0, date("m", $time_min), date("d", $time_min)+$i+1, date("Y", $time_min)); 
    $query = ".."; 
    $output = date("m-d-y", ..); 
} 

지금까지 내 생각은 무엇입니까? 하루 (20091212), 월 (200912), 주 (200942) 및 연도 (2009)에 대한 추가/중복 열 (INTEGER)을 추가하십시오. 이렇게하면 for 루프에서 불필요한 쿼리를 모두 제거 할 수 있습니다. 그러나 나는 데이터베이스에서 동등한 가치가없는 모든 날짜를 매우 빨리 계산하기 위해 여전히 문제에 직면 해있다. 문제를 단순히 이동시키는 한 가지 방법은 MySQL이 작업을 수행하고 왼쪽 조인 (데이터)을 사용하여 간단한 쿼리 (모든 날짜 계산/MySQL 날짜 함수 사용)를 사용하는 것입니다. MySQL에 추가로드를 허용하는 것이 현명한 방법일까요? 어쨌든 for 루프에서 이러한 모든 mktime/date를 사용하기를 꺼립니다. 필자는 테이블 레이아웃과 코드를 완벽하게 제어 할 수 있으므로 주요 변경 사항을 제안해도 좋습니다. 그렉에

업데이트

덕분에 나는 다음과 같은 SQL 쿼리를 함께했다. 당신은 확실히 루프 내부 쿼리를 수행해서는 안

SELECT * FROM ( 
    SELECT DATE_ADD('2009-01-30', INTERVAL 0 DAY) AS day UNION ALL 
    SELECT DATE_ADD('2009-01-30', INTERVAL 1 DAY) AS day UNION ALL 
    SELECT DATE_ADD('2009-01-30', INTERVAL 2 DAY) AS day UNION ALL 
    SELECT DATE_ADD('2009-01-30', INTERVAL 3 DAY) AS day UNION ALL 
    ...... 
    SELECT DATE_ADD('2009-01-30', INTERVAL 50 DAY) AS day) AS dates 
LEFT JOIN (
    SELECT DATE_FORMAT(date, '%Y-%m-%d') AS date, SUM(data) AS data 
    FROM test 
    GROUP BY date 
) AS results 
ON DATE_FORMAT(dates.day, '%Y-%m-%d') = results.date; 

답변

1

: - PHP로 구축 - 어쩌면 더 우아하게, 그렇지 않으면 빠르게 수행 할 수 그러나 여전히 버그 나 SQL 문의 50 개 라인을 사용합니다. 당신은이 같은 그룹 수 있습니다 : 당신이하고있는 것처럼

SELECT COUNT(*) AS count, SUM(important_data) AS important_data, DATE_FORMAT('%Y-%m', date) AS month 
    FROM my_table 
    WHERE date BETWEEN ? AND ? -- This should be the min and max of the whole range 
    GROUP BY DATE_FORMAT('%Y-%m', date) 
    ORDER BY date DESC; 

그런 다음 데이터를 통해 날짜와 루프에 의해 키가 배열로이 끌어 범위 (즉, 루프는 CPU에 꽤 빛이어야한다).

+0

감사합니다! DATE_FORMAT를 성공적으로 사용하려면 INTEGER에서 DATETIME으로 전환해야하기 때문에 아이디어를 테스트하는 데 어느 정도 시간이 걸릴 것입니다. 그러나 그것은 유망 해 보인다. 한 가지가 누락되었다고 오인하지 않으면 테이블에 항목이없는 모든 날짜를 어떻게 얻습니까? 예 : 2009-10 및 2009-11에 대한 데이터가 있지만 2009-12는 비어 있지만 표시되어야합니다.내가 이것에 대한 PHP 기능으로 돌아 가야합니까 아니면 이것에 대한 우아한 mysql 솔루션이 있습니까? – merkuro

+0

@merkuro : 거기에있는 데이터 만 출력 할 수 있습니다. 누락 된 레코드는 마술처럼 나타나지 않습니다. 만약 당신이 일년 중 매일 기록을 남기고 싶다면 캘린더 테이블을 만들고 그것에 대한 외부 조인을하십시오. 이러한 테이블은 한 번만 작성되고 채워질 필요가 있으며 연간 365 개의 행이 필요합니다. 이 방법으로 출력에서 ​​"갭"이 사라집니다. – Tomalak

+0

@Tomalak 당신은 MySQL 설치가 통합 된 마술사와 함께 오지 않는다는 것을 의미합니까? 솔직히, 무슨 목적으로 너의 snarky 코멘트가 있었나요? 왼쪽 결합을 사용하는 옵션에 대해서는 이미 언급했는데 디스크 사용량이 증가했기 때문에이 솔루션에서 잠재적 인 성능 문제가 있음을 알았습니다. 어쨌든 나는 누군가가 간과 한 기능과 같은 멋진 범위/배열을 생각해 내기를 바랐다. – merkuro

관련 문제