我有一个数据库表,每天接收近100万个插件,需要至少一年才能搜索到。大硬盘和大量数据,而不是那么好的硬件。
表格如下:
id | tag_id | value | time
----------------------------------------
279571 55 0.57 2013-06-18 12:43:22
...
tag_id
可能类似于AmbientTemperature
或AmbientHumidity
,并且从传感器读取时会捕获时间。
我正在以报告格式查询此表。我希望在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天的数据集可能需要几分钟。
答案 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);
需要考虑的其他一些事项:
答案 2 :(得分:0)
我不是sqlserver的专家,但我会认真考虑将其设置为分区表。这也可以简化归档,因为可以简单地删除分区(而不是从哪里删除昂贵的代码)。
另外(运气好的话)优化器只会查看数据所需的分区。