쿼리의 일부는 오랫동안 CPU를 최대로 늘리는 것입니다. GROUP BY 절의 함수이며 그룹화는 항상이 인스턴스에서 인덱싱되지 않은 정렬이 필요하다는 사실입니다. 타임 스탬프 필드의 인덱스는 초기 필터에 도움이되지만 필터와 일치하는 모든 행에서이 작업을 수행해야합니다. 이 속도를 높이는 것은 Alex가 제안한 것과 동일한 작업을 수행하기 위해보다 효율적인 경로를 사용하지만 쿼리 플래너를 사용하는 기능 조합이 나오지 않기 때문에 여전히 비효율적입니다. 어떤 인덱스가 도움이 될 것이므로 그룹화 값을 계산하기 위해 먼저 함수를 실행하는 모든 행을 실행해야합니다. 그러면 데이터를 정렬하고 결과 그룹화에 대한 집계를 계산할 수 있습니다.
따라서 해결책은 프로세스 그룹이 색인을 사용할 수있는 방법으로 프로세스 그룹을 만들거나 일치하는 모든 행을 한 번에 고려해야 할 필요성을 제거하는 것입니다.
시간을 반올림 한 시간을 포함하는 각 행에 대해 여분의 열을 유지 관리하고 이러한 쿼리에 사용하기 위해이 열을 색인화 할 수 있습니다. 이것은 데이터를 비정규 화하고 있으므로 "더러운"느낌이 들지만 나중에 사용할 수 있도록 모든 집계를 캐싱하는 것 (및 기본 데이터가 변경 될 때 해당 캐시를 업데이트하는 것)보다 더 깨끗하고 효과적입니다. 여분의 열은 데이터를 삽입하거나 타임 스탬프 열 또는 기존 행을 업데이트 할 수있는 현재 및 미래의 모든 장소가 새로운 데이터에서 일관된 데이터를 생성 할 수 있기 때문에 다른 곳에서는 논리에 의해 유지되는 것이 아니라 트리거에 의해 유지되거나 지속적으로 계산 된 열이어야합니다. 기둥. 여전히 MIN (타임 스탬프)을 가져올 수 있습니다. 쿼리가 이런 식으로 결과를 얻는 것은 여전히 모든 행을 걸어 내려가는 것입니다 (물론 피할 수는 없지만) 인덱스 순서를 수행 할 수 있습니다. 그룹화 / 집계를 수행하기 전에 인덱싱되지 않은 정렬 작업을 위해 전체 행 집합을 기억할 필요없이 인덱스의 다음 값에 도달 할 때 각 그룹화에 대한 행을 출력합니다. 현재보고있는 값이나 나머지 부분을 처리하기 위해 이전 그룹화 값의 행을 기억할 필요가 없으므로 메모리도 훨씬 적게 사용합니다.
이 방법을 사용하면 전체 결과 집합에 대해 메모리에서 어딘가를 찾을 필요가 없으며 그룹 작업에 대해 색인화되지 않은 정렬을 수행하고 큰 쿼리에서 그룹 값 계산을 제거합니다 (작업을 해당 작업을 생성하는 개별 INSERT / UPDATE로 이동). 데이터)) 집계 된 결과의 별도 저장소를 유지할 필요없이 이러한 쿼리를 수용 가능하게 실행할 수 있어야합니다.
그렇지 않은 방법데이터를 비정규 화하지만 여전히 추가 구조가 필요한 경우에는 "시간표"(이 경우 시간당 한 행씩 포함 된 행)를 사용하는 것이 좋습니다. 이 테이블은 DB 또는 상당한 크기의 공간을 많이 소비하지 않습니다. 두 날짜의 한 행 (시간의 시작과 끝, 예 : '2011-01-01 @ 00 : 00 : 00.0000 ','2011-01-01 @ 00 : 00 : 59.9997 ', "9997"은 DATETIME 필드가 다음 초로 반올림되지 않는 최소 밀리 초입니다. 클러스터 된 기본 키는 ~ 14Mbyte의 공간을 차지합니다 (행당 8 + 8 바이트 * 24 시간 / 일 * 365.25 일 / 년 * 100). .
SELECT CONVERT(VARCHAR, [timestamp], 1)+' '+ CAST(DATEPART(Hh,[timestamp]) as VARCHAR) AS TimeStampHour
, MIN([timestamp]) as TimeStamp
, AVG(MyField) As AvgField
FROM TimeRangeByHours tt
INNER JOIN MyData md ON md.TimeStamp BETWEEN tt.StartTime AND tt.EndTime
WHERE tt.StartTime > '4/10/2011'
GROUP BY tt.StartTime
ORDER BY tt.StartTime
이는 쿼리 플래너가 MyData.TimeStamp의 인덱스를 사용하도록 정렬 할 수 있음을 의미합니다. 쿼리 플래너는 MyData.TimeStamp의 인덱스를 사용하여 단계적으로 길들이기 테이블을 걸을 수 있도록 그룹화 할 수있을 정도로 밝아 야합니다. 그룹 화당 하나의 행을 다시 출력하고 다음 그룹화 값에 도달하면 각 세트를 삭제합니다. RAM의 어딘가에 모든 중간 행을 저장하지 않고 색인화되지 않은 정렬을 수행하지 않습니다. 물론이 방법을 사용하려면 시간표를 작성하여 시간이 앞뒤로 충분히 넓어야하지만 "추가 열"옵션과 같이 다른 쿼리의 여러 날짜 필드에 대한 쿼리에 시간표를 사용할 수 있습니다. 이러한 방식으로 필터링 / 그룹화해야하는 각 날짜 필드에 대한 추가 계산 열과 테이블의 작은 크기 (10 개 범위에 걸쳐 필요하지 않은 경우)
시간표 방법은 현재 상황 및 계산 된 열 솔루션과 비교할 때 추가 이점 (매우 유리할 수 있음)이 있습니다. 위의 예제 쿼리에서 INNER JOIN을 변경하여 데이터가없는 기간 동안 행을 리턴 할 수 있습니다. 왼쪽 외부가됩니다.
어떤 사람들은 물리적 시간표가 없지만 항상 테이블 반환 함수에서 반환하는 것이 좋습니다. 이것은 시간표의 내용이 디스크에 저장되거나 읽혀질 필요가 없다는 것을 의미하며 함수가 제대로 작성되면 시간표가 시간과 시간에 얼마나 오래 걸리는지 걱정할 필요가 없습니다. 의심의 여지없이 모든 행에 대해 메모리 내 테이블을 생성하는 CPU 비용이 실제 시간 테이블을 생성 (및 초기 버전의 한계를 초과하여 확장해야 할 경우 유지 관리해야하는 번거 로움)를 줄일 가치가 있습니다.
참고 사항 : 원래 쿼리에 DISTINCT 절이 필요하지 않습니다. 그룹화는 이러한 쿼리가 고려중인 기간 당 하나의 행만 리턴하도록 보장하므로 DISTINCT는 CPU를 조금 더 회전시키는 것 외에는 아무 것도 수행하지 않습니다 (쿼리 플래너가 구별이 아무 문제가 없음을 통지하지 않는 한) 무시하고 추가 CPU 시간을 사용하지 마십시오).