2013-11-21 177 views
0

我有一个数据库表,每天接收近100万条插入,至少需要一年可搜索。大硬盘和大量数据,而不是那么棒的硬件。优化SQL Server查询/表

表看起来是这样的:

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天的数据集。

+1

更好地使用您的群集主键索引。以下内容可能会引起您的兴趣:http://technet.microsoft.com/zh-CN/library/aa933131(v=sql.80).aspx和http://stackoverflow.com/questions/4419499/mysql-and- nosql -help-me-to-choose-the-right-one/4421601#4421601和http://stackoverflow.com/questions/5451190/60-million-entries-select-entries-from-a-certain-month-如何优化数据库/ 5451389#5451389 –

回答

0

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

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

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

过滤的行数函数的结果将会使查询十分缓慢。它也会阻止最佳的索引使用。

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

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或日期进行分区。
  • 除了使用IsHourlySensorReading指标创建列以外,还可以为特定的报告要求创建单独的表/数据库,并仅将相关数据加载到该列中。
+0

我不能在答案中添加“每小时”列。规范要求数据查看器工具以用户喜欢的任何间隔显示数据。每小时,每天,每半小时,每秒钟等等。表格分区需要企业,如果报表按时间顺序显示传感器读数 - 没有其他意义,这将是非常好的。 –