2016-10-05 7 views
0

에 쿼리를 최적화하는 데 도움이 필요 :나는 다음과 같은 구조의 테이블이 긴 테이블

CREATE TABLE [dbo].[readings] 
(
    [facilityId] int NOT NULL , 
    [deviceId] int NOT NULL , 
    [reading] real NULL , 
    [insertionTimestamp] datetime2(7) NOT NULL 
) 
GO 

CREATE CLUSTERED INDEX [readings_index] 
    ON [dbo].[readings] ([facilityId] ASC, [deviceId] ASC) 
GO 

내가 더 기본 키가 없습니다. 내가 가진다면 facilityId, deviceIdinsertionTimestamp이 될 것입니다. 그러나 나는 테이블의 각 INSERTion에서이 필드의 고유성을 확인하여 삽입을 훨씬 느리게 만드는 것을 두려워합니다.

내가 겪고있는 문제는이 테이블이 매우 길다는 것입니다. 이 순간 나는 거의 백만 기록을 가지고 있으며 다음 쿼리를 해결 팔초합니다 : 다른이 쿼리가 실행될 때마다

SELECT 
    MAX(reading) as reading, deviceId, 
    FORMAT(insertionTimestamp, 'yyyy-MM-dd HH:00:00') as TS, 
    DATEPART(year, insertionTimestamp) as year 
FROM 
    readings 
WHERE 
    deviceId IN (12, 15, 18, 19, 22, 27, 28, 29, 32, 35, 36, 39, 42, 43, 46, 47, 50, 53, 54, 57, 61, 64, 65, 68, 71, 72, 75, 76, 79, 80, 83, 86, 87) 
    AND facilityId = 1 
    AND insertionTimestamp BETWEEN '2016-10-04 23:12:22.121' AND '2016-10-05 23:12:22.138' 
GROUP BY 
    deviceId, FORMAT(insertionTimestamp, 'yyyy-MM-dd HH:00:00'), 
    DATEPART(year, insertionTimestamp) 

장치 ID와 insertionTimestamp 경계 BETWEEN을.

나는 무엇이든 최적화 할 수 있는지 알아보기 위해 EXPLAIN을 보았습니다. 아무 것도 내 마음에 오지 않습니다.

enter image description here

내가 무엇을 할 수 있습니까?

감사합니다.

+0

insertTimestamp의 'NONCLUSTERED'색인은 분명 도움이되지만 INSERT 속도와 READ/QUERY 속도 사이의 균형을 유지할 수 있습니다. 어느 것이 더 중요합니까? – SqlOnly

+0

읽기가 훨씬 더 중요하지만 삽입은 또한 적절한 시간 범위 내에서 발생해야합니다 (그리고 오랫동안 삽입이 계속 읽기 작업에도 영향을 미칠 것입니다). 당신은 insertionTimestamp 컬럼에 대해서만 'NONCLUSTERED'인덱스를 생성 할 것을 제안하고 있습니까? 그 배후에있는 추론을 간단히 설명하여 제가 배울 수 있습니까? 감사! – PedroD

+0

다른 모든 옵션보다 반드시 권장하지는 않습니다. 나는 또한 3 개의 칼럼 모두에서 'NONCLUSTERED'색인을 고려할 것이다. 임시 테이블/대체 테이블로 데이터를 옮기고 하나의 열에 인덱스를 적용하여 INSERT 및 SELECT 성능을 테스트하는 테스트를 직접 수행 할 것입니다. 그런 다음 3 개의 열 모두에 인덱스를 적용하고 (다른 단일 열 인덱스 제거) 테스트를 반복 한 다음 가장 합리적인 조치 과정을 결정합니다. – SqlOnly

답변

0

내적 선택이 대부분의 데이터를 걸러 내고 더 작은 데이터 세트에서 실행되는 외부 쿼리에서 계산을 실행하면 제안 만하지만 속도를 향상시킬 수 있습니다. 800 만 개 기록 중 내부 선택 반환 7 백만이, 그것도 할 수있는 경우 그것은 더 :

SELECT MAX(reading) as reading, deviceId, FORMAT(insertionTimestamp, 'yyyy-MM-dd HH:00:00') as TS, DATEPART(year, insertionTimestamp) as year 
FROM (SELECT reading, deviceID, insertionTimestamp 
     FROM readings 
     WHERE deviceId IN (12,15,18,19,22,27,28,29,32,35,36,39,42,43,46,47,50,53,54,57,61,64,65,68,71,72,75,76,79,80,83,86,87) 
     AND facilityId = 1) i 
WHERE insertionTimestamp BETWEEN '2016-10-04 23:12:22.121' AND '2016-10-05 23:12:22.138' 
GROUP BY deviceId, FORMAT(insertionTimestamp, 'yyyy-MM-dd HH:00:00'), DATEPART(year, insertionTimestamp) 
+0

조인 절 . –

0

나는 인덱스의 세 where 열을 가진 제안 만이 직접 사용할 수 있지만. 그런 다음 SELECT에서 추가 열을 넣으십시오.

시간 프레임은 비교적 작아 보입니다. 따라서 두 번째 열 (readings(facilityId, insertionTimestamp, deviceId, reading))이어야합니다. 마지막 두 항목은 키에 포함되지 않고 색인에 포함될 수 있습니다.

SELECT MAX(reading) as reading, deviceId, 
     FORMAT(insertionTimestamp, 'yyyy-MM-dd HH:00:00') as TS, 
     DATEPART(year, insertionTimestamp) as year 
FROM readings 
WHERE deviceId IN (12,15,18,19,22,27,28,29,32,35,36,39,42,43,46,47,50,53,54,57,61,64,65,68,71,72,75,76,79,80,83,86,87) AND 
     facilityId = 1 AND 
     insertionTimestamp BETWEEN '2016-10-04 23:12:22.121' AND '2016-10-05 23:12:22.138' 
GROUP BY deviceId, FORMAT(insertionTimestamp, 'yyyy-MM-dd HH:00:00'), DATEPART(year, insertionTimestamp); 
관련 문제