2017-08-05 30 views
4

我有一個用於我們的IOT指標(時間序列數據)的集羣列存儲索引表。它包含超過10億行,結構如下:如何優化SQL Server列存儲對齊

CREATE TABLE [dbo].[Data](
[DeviceId] [bigint] NOT NULL, 
[MetricId] [smallint] NOT NULL, 
[TimeStamp] [datetime2](2) NOT NULL, 
[Value] [real] NOT NULL 
) 

CREATE CLUSTERED INDEX [PK_Data] ON [dbo].[Data] ([TimeStamp],[DeviceId],[MetricId]) --WITH (DROP_EXISTING = ON) 
CREATE CLUSTERED COLUMNSTORE INDEX [PK_Data] ON [dbo].[Data] WITH (DROP_EXISTING = ON, MAXDOP = 1, DATA_COMPRESSION = COLUMNSTORE_ARCHIVE) 

從2008年到現在,有大約10,000個不同的DeviceId值和TimeStamps範圍。針對此表中典型的查詢看起來是這樣的:

SET STATISTICS TIME, IO ON 
SELECT 
    [DeviceId] 
    ,[MetricId] 
    ,DATEADD(hh, DATEDIFF(day, '2005-01-01', [TimeStamp]), '2005-01-01') As [Date] 
    ,MIN([Value]) as [Min] 
    ,MAX([Value]) as [Max] 
    ,AVG([Value]) as [Avg] 
    ,SUM([Value]) as [Sum] 
    ,COUNT([Value]) as [Count] 
FROM 
    [dbo].[Data] 
WHERE 
    [DeviceId] = 6077129891325167032 
    AND [MetricId] = 1000 
    AND [TimeStamp] BETWEEN '2017-07-01' AND '2017-07-30' 
GROUP BY 
    [DeviceId] 
    ,[MetricId] 
    ,DATEDIFF(day, '2005-01-01', [TimeStamp]) 
ORDER BY 
    [DeviceId] 
    ,[MetricId] 
    ,DATEDIFF(day, '2005-01-01', [TimeStamp]) 

當我執行此查詢,我得到這樣的性能指標:

因爲此刻像上述查詢做太多的段讀我相信:

Table 'Data'. Scan count 2, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 5257, lob physical reads 9, lob read-ahead reads 4000. 
Table 'Data'. Segment reads 11, segment skipped 764. 

查詢計劃: Query plan

這不是很好的優化,我相信,因爲w ^在分組/集合之前,只讀取11個分段中的212個分段

然後我運行Niko Neugebauer的優秀腳本來驗證我們的設置和Columnstore對齊https://github.com/NikoNeugebauer/CISL/blob/master/Azure/alignment.sql,重建Columnstore後我得到了這個結果聚集索引:

Columnstore Alignment

MetricId和時間戳列有100%的最佳比對得分。我們如何確保DeviceId列也很好地對齊?我在初始的Clustered(Rowstore)索引中使用了列順序,是否可以優化事物?

+0

請貼查詢計劃,XML以及 – TheGameiswar

+0

如果您正在使用SQL Server 2016年,嘗試使用DBCC clonedb和共享數據庫,以便其他人可以瑞普你facing.if你不使用2016年確切的情況,你可以腳本我們的表架構,索引,統計數據和嘗試共享腳本 – TheGameiswar

+1

@TheGameiswar [DBCC CLONEDATABASE](HTTPS ://support.microsoft.com/en-gb/help/3177838/how-to-use-dbcc-clonedatabase-to-generate-a-schema-and-statistics-only)可從SQL Server 2014 SP2起: ) – wBob

回答

5

通過DeviceId對齊表的關鍵解決方案是在您的表上構建一個集羣行存儲索引,然後在其上構建一個MAXDOP = 1的集羣Columnstore索引(爲了不引入索引構建時發生的任何重疊運行多個核心)。 所以可能的代碼會是這個樣子:

CREATE CLUSTERED INDEX [PK_Data] ON [dbo].[Data] ([DeviceId],[TimeStamp],[MetricId]) --WITH (DROP_EXISTING = ON) 
CREATE CLUSTERED COLUMNSTORE INDEX [PK_Data] ON [dbo].[Data] WITH (DROP_EXISTING = ON, MAXDOP = 1, DATA_COMPRESSION = COLUMNSTORE_ARCHIVE) 

另一種可能是做這一切CISL內,通過準備,然後執行對齊funcitonality:

insert into dbo.cstore_Clustering(TableName, Partition, ColumnName) 
    VALUES ('[dbo].[Data]', 1, 'DeviceId'); 

這雖然只是1分區,但是您應該考慮分區表,無論如何,一旦你進入你正在使用的數字。 設置完成後,您可以開始執行dbo.cstore_doAlignment,它將自動重新對齊並優化您的表格。 (你將有一些參數來配置的優化的門檻,如果你喜歡)

最好的問候, 尼科

+0

謝謝@妮可。因此,我正確理解您的答案,對於我們的IOT指標中只有「僅附加」/日誌記錄表的情況,我們應該使用TimeStamp列(每月?)對錶進行分區,並且通過DeviceId對齊此表? 在我們的聚合中,我們總是查詢一個DeviceId,可能有多個不同的MetricId和一個時間範圍爲1個月或12個月(分別按小時和天分組)的TimeStamp。 –

+0

泰德, 沒有所有的小細節(這可能會改變我的看法),我同意它看起來像TimeStamp分區和通過DeviceId對齊看起來像一個很好的選擇。 此致敬禮, Niko –

+0

非常感謝你,@尼科!我已在TimeStamp上每月實施分區,並通過DeviceId進行對齊。結果是有希望的,但確實需要一些額外的驗證,因爲大多數(75%)查詢在100ms內運行在<之間,但是25%需要2,000ms。介於兩者之間的不多。它們都在Premium Azure SQL彈性池上運行。因此,這是相同的查詢,每3秒執行一次,因此不會遇到節流餘量。 你對分區部分行數量有何建議?我現在選擇月份,但也許會導致分區數量太多? –