需要帮助优化长表上的查询

时间:2016-10-05 22:35:30

标签: sql sql-server sql-server-2008

我有一个具有以下结构的表:

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

我没有主键。如果我有,他们将是facilityIddeviceIdinsertionTimestamp。但是我害怕让它在表中的每个INSERTion中验证这些字段的唯一性,使插入速度慢得多。

我遇到的问题是这张桌子非常长。此刻我有近一百万条记录,需要8秒才能解析以下查询:

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和insertedTimestamp BETWEEN边界都不同。

我试着看看EXPLAIN,看看我是否可以优化任何东西......没有什么事情在我脑海中浮现。

enter image description here

我该怎么办?

谢谢!

2 个答案:

答案 0 :(得分:0)

只是一个建议,但如果内部选择过滤掉大部分数据并且您在外部查询上运行计算,这样可能会提高速度,外部查询将在更小的数据集上运行。但如果内部选择在800万条记录中返回700万条,那么它甚至可能会使情况变得更糟:

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)

答案 1 :(得分: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);