2013-11-21 252 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

我不能在答案中添加「每小時」列。規範要求數據查看器工具以用戶喜歡的任何間隔顯示數據。每小時,每天,每半小時,每秒鐘等等。表格分區需要企業,如果報表按時間順序顯示傳感器讀數 - 沒有其他意義,這將是非常好的。 –