2011-03-28 82 views
0

我有一個超過一億行的巨大表格,我必須查詢此表格才能在最短的時間內返回一組數據。在閱讀巨大表格時的性能調整

所以我創建了一個測試環境,這個表的定義:

CREATE TABLE [dbo].[Test](
[Dim1ID] [nvarchar](20) NOT NULL, 
[Dim2ID] [nvarchar](20) NOT NULL, 
[Dim3ID] [nvarchar](4) NOT NULL, 
[Dim4ID] [smalldatetime] NOT NULL, 
[Dim5ID] [nvarchar](20) NOT NULL, 
[Dim6ID] [nvarchar](4) NOT NULL, 
[Dim7ID] [nvarchar](4) NOT NULL, 
[Dim8ID] [nvarchar](4) NOT NULL, 
[Dim9ID] [nvarchar](4) NOT NULL, 
[Dim10ID] [nvarchar](4) NOT NULL, 
[Dim11ID] [nvarchar](20) NOT NULL, 
[Value] [decimal](21, 6) NOT NULL, 
CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED 
(
[Dim1ID] ASC, 
[Dim2ID] ASC, 
[Dim3ID] ASC, 
[Dim4ID] ASC, 
[Dim5ID] ASC, 
[Dim6ID] ASC, 
[Dim7ID] ASC, 
[Dim8ID] ASC, 
[Dim9ID] ASC, 
[Dim10ID] ASC, 
[Dim11ID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

此表是星型模式架構(事實上/尺寸)的事實表。正如你所看到的,除了「Value」列之外,我在所有列上都有一個聚集索引。

我已經用大約填充了這些數據。 10,000,000行用於測試目的。碎片率目前爲0.01%。

我想使用此查詢從該表中讀取的行集時提高性能:

DECLARE @Dim1ID nvarchar(20) = 'C1' 
DECLARE @Dim9ID nvarchar(4) = 'VRT1' 
DECLARE @Dim10ID nvarchar(4) = 'S1' 
DECLARE @Dim6ID nvarchar(4) = 'FRA' 
DECLARE @Dim7ID nvarchar(4) = '' -- empty = all 
DECLARE @Dim8ID nvarchar(4) = '' -- empty = all 

DECLARE @Dim2 TABLE (Dim2ID nvarchar(20) NOT NULL) 
INSERT INTO @Dim2 VALUES ('A1'), ('A2'), ('A3'), ('A4'); 

DECLARE @Dim3 TABLE (Dim3ID nvarchar(4) NOT NULL) 
INSERT INTO @Dim3 VALUES ('P1'); 

DECLARE @Dim4ID TABLE (Dim4ID smalldatetime NOT NULL) 
INSERT INTO @Dim4ID VALUES ('2009-01-01'), ('2009-01-02'), ('2009-01-03'); 

DECLARE @Dim11 TABLE (Dim11ID nvarchar(20) NOT NULL) 
INSERT INTO @Dim11 VALUES ('Var0001'), ('Var0040'), ('Var0060'), ('Var0099') 

SELECT RD.Dim2ID, 
     RD.Dim3ID, 
     RD.Dim4ID, 
     RD.Dim5ID, 
     RD.Dim6ID, 
     RD.Dim7ID, 
     RD.Dim8ID, 
     RD.Dim9ID, 
     RD.Dim10ID, 
     RD.Dim11ID, 
     RD.Value 
FROM  dbo.Test RD 
     INNER JOIN @Dim2 R 
      ON RD.Dim2ID = R.Dim2ID 
     INNER JOIN @Dim3 C 
      ON RD.Dim3ID = C.Dim3ID 
     INNER JOIN @Dim4ID P 
      ON RD.Dim4ID = P.Dim4ID 
     INNER JOIN @Dim11 V 
      ON RD.Dim11ID = V.Dim11ID 
WHERE RD.Dim1ID = @Dim1ID 
     AND RD.Dim9ID = @Dim9ID 
     AND ((@Dim6ID <> '' AND RD.Dim6ID = @Dim6ID) OR @Dim6ID = '') 
     AND ((@Dim7ID <> '' AND RD.Dim7ID = @Dim7ID) OR @Dim7ID = '') 
     AND ((@Dim8ID <>'' AND RD.Dim8ID = @Dim8ID) OR @Dim8ID = '') 

我已經測試過該查詢和所​​返回180行這些時間: 1日執行: 1分32秒;第二次執行:1分鐘

如果可能,我想在幾秒鐘內返回數據。

我想我可以添加非聚集索引,但我不知道最好的方法是設置非聚集索引! 如果在此表中排序了訂單數據可以提高績效? 還是有其他解決方案比索引?

謝謝。

+0

腦融化。什麼是變量命名? – 2011-03-28 16:26:36

+0

爲了保密,我寧願不要輸入真實姓名。但我想我可以寫出虛擬名字。 – Dan 2011-03-28 16:45:38

回答

3

考慮您的數據類型爲一個問題。 Do you need nvarchar?這是measurably slower

問題二:PK是錯誤的查詢,它應該是Dim1ID, Dim9ID第一(或反之亦然基於選擇性)。或一些味道與JOIN列中。

第三個問題:使用或。儘管沒有嘗試過的人會說話,但這個構造通常是有效的。

RD.Dim7ID = ISNULL(@Dim7ID, RD.Dim7ID) 

這是假定@ Dim7ID是NULL雖然。優化器會在大多數情況下將其短路。

0

看到這一點:Dynamic Search Conditions in T-SQL Version for SQL 2008 (SP1 CU5 and later)

快速的解答,如果您是在SQL Server 2008中的正確的服務包,就是 嘗試添加到查詢的末尾:

OPTION(RECOMPILE) 

當SQL Server 2008的正確Service Pack,OPTION(RECOMPILE)將根據本地變量的運行時值構建執行計劃。

對於人於2005年見猶使用SQL Server 2008沒有正確的服務包或靜止:Dynamic Search Conditions in T-SQLVersion for SQL 2005 and Earlier

0

我會有點關心你的聚集索引中的所有非價值列。這將在非葉級別上形成一個大的索引。而且,該密鑰將用於非聚集索引。而且,只有當查詢中包含[Dim1ID]時,它纔會提供任何好處。所以,即使你只是優化這個查詢,你可能會得到一個完整的掃描。

我會考慮最常用的鍵上的聚集索引,如果您有很多與日期相關的查詢(例如,a和b之間的日期),請使用日期鍵。然後,在其他鍵值上創建非聚集索引。

+0

我們在關鍵和十億行+中有更多列的類似表格。對於OLAP類型的表,這是正常的。 – gbn 2011-03-28 16:44:24

2

我與gbn在此。通常在星型模式數據倉庫中,維度ID是int,即4個字節。不僅所有的尺寸都大於這個尺寸,nvarchar都是變化的並且使用寬字符。

就索引而言,只有一個聚類索引可能沒有問題,因爲在事實表的情況下,您確實沒有太多事實。正如gbn所說的,在你的特定例子中,你的索引需要按照你將要提供的列的順序,這樣索引才能真正被使用。

在一個事實表中,有許多事實的實際情況,您的聚集索引僅僅是數據組織 - 您可能會期望一些非聚集索引的具體用法。

但我擔心你的查詢指定了一個ID參數。通常,在DW環境,你不知道的ID,選擇性查詢,請根據尺寸,和IDS是沒有意義的替代品:

SELECT * 
FROM fact 
INNER JOIN dim1 
    ON fact.dim1id = dim1.id 
WHERE dim1.attribute = '' 

你看着金博爾對三維建模的書?我認爲,如果你要選擇一個明星模式,你應該熟悉他的設計技巧,以及他討論的太多和太少的缺陷。