优化SQL Server查询/表

时间:2013-11-21 14:52:58

标签: sql sql-server tsql indexing query-optimization

我有一个数据库表,每天接收近100万个插件,需要至少一年才能搜索到。大硬盘和大量数据,而不是那么好的硬件。

表格如下:

id      | tag_id  |  value  |  time 
----------------------------------------
279571     55         0.57    2013-06-18 12:43:22
...

tag_id可能类似于AmbientTemperatureAmbientHumidity,并且从传感器读取时会捕获时间。

我正在以报告格式查询此表。我希望在2013-11-1和2013-11-28之间以1小时的间隔查看标签1,55,72和4的所有数据。

SELECT time, tag_id, tag_name, value, friendly_name
FROM (
    SELECT time, tag_name, tag_id, value,friendly_name, 
        ROW_NUMBER() over (partition by tag_id,datediff(hour, 0, time)/1 order by time desc) as seqnum
    FROM tag_values tv 
    JOIN tag_names tn ON tn.id = tv.tag_id
    WHERE (tag_id = 1 OR tag_id = 55 OR tag_id = 72 OR tag_id = 4)
        AND time >= '2013-11-1' AND time < '2013-11-28'
    ) k
WHERE seqnum = 1
ORDER BY time";

我可以优化此表格或查询吗?我该如何设置索引?

桌面大小为1亿+行,速度很慢。在查询中使用3个标记每小时一段时间获取7天的数据集可能需要几分钟。

3 个答案:

答案 0 :(得分:1)

  

我应该如何设置索引?

我会尝试遵循索引:

CREATE /*UNIQUE*/ INDEX IX_MyTable_tag_id_time -- If this index could be unique then uncomment UNIQUE
ON dbo.tag_values (tag_id, time)
INCLUDE (value) -- Covered column
WITH (FILLFACTOR = 90); -- Needed to minimize page splits. You should test other values for fill factor to find optimum value for your workload. 90 is just an example. Default value is usually 0 or 100 (see http://technet.microsoft.com/en-us/library/ms190470.aspx) 
GO

答案 1 :(得分:1)

过滤行号函数的结果会使查询变得非常缓慢。此外,它将阻止最佳索引使用。

如果您的主要报告需求是每小时信息,您可能需要考虑存储哪些行是特定小时内标记的第一个传感器读数。

ALTER TABLE tag_values ADD IsHourlySensorReading BIT NULL;

在每小时的过程中,您为新行计算此列。

DECLARE @CalculateFrom DATETIME = (SELECT MIN(time) FROM tag_values WHERE IsHourlySensorReading IS NULL);
SET @CalculateFrom = dateadd(hour, 0, datediff(hour, 0, @CalculateFrom));

UPDATE k
SET IsHourlySensorReading = CASE seqnum WHEN 1 THEN 1 ELSE 0 END
FROM (
    SELECT id, row_number() over (partition by tag_id,datediff(hour, 0, time)/1 order by time desc) as seqnum
    FROM tag_values tv
    WHERE tv.time >= @CalculateFrom
    AND tv.IsHourlySensorReading IS NULL
) as k

您的报告查询会变得更加简单:

SELECT time, tag_id, tag_name, value, friendly_name
FROM (
    SELECT time, tag_name, tag_id, value,friendly_name
    FROM tag_values tv 
    JOIN tag_names tn ON tn.id = tv.tag_id
    WHERE (tag_id = 1 OR tag_id = 55 OR tag_id = 72 OR tag_id = 4)
        AND time >= '2013-11-1' AND time < '2013-11-28'
        AND IsHourlySensorReading=1
    ) k
ORDER BY time;

以下索引将有助于计算IsHourlySensorReading列。但请记住,索引也会导致每天百万次插入需要更多时间。彻底测试!

CREATE NONCLUSTERED INDEX tag_values_ixnc01 ON tag_values (time, IsHourlySensorReading) WHERE (IsHourlySensorReading IS NULL);

如果您需要按时间顺序,请使用此索引进行报告。

CREATE NONCLUSTERED INDEX tag_values_ixnc02 ON tag_values (time, tag_id, IsHourlySensorReading) INCLUDE (value) WHERE (IsHourlySensorReading = 1);

如果您不需要按时间顺序,请使用此索引进行报告。

CREATE NONCLUSTERED INDEX tag_values_ixnc02 ON tag_values (tag_id, time, IsHourlySensorReading) INCLUDE (value) WHERE (IsHourlySensorReading = 1);

需要考虑的其他一些事项:

  • 真的需要ORDER BY时间吗?
  • 表分区可以严重提高插入和查询性能。根据您的情况,我会在tag_id或date上进行分区。
  • 您可以为特定的报告要求创建单独的表/数据库,而不是创建具有IsHourlySensorReading指标的列,而只是将相关数据加载到该列中。

答案 2 :(得分:0)

我不是sqlserver的专家,但我会认真考虑将其设置为分区表。这也可以简化归档,因为可以简单地删除分区(而不是从哪里删除昂贵的代码)。

另外(运气好的话)优化器只会查看数据所需的分区。