2010-02-01 53 views
4

我有一個非常大的表(10多萬行),開始顯示查詢性能下降的跡象。由於這張表格的尺寸可能會很快增加一倍或三倍,我正在研究對錶格進行分區以擠出一些查詢性能。基於模數函數的SQL Server表分區?

表看起來是這樣的:

CREATE TABLE [my_data] (
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [topic_id] [int] NULL, 
    [data_value] [decimal](19, 5) NULL 
) 

所以,一堆對於任何給定主題值。此表上的查詢將始終按主題ID進行查詢,因此(id,topic_id)上有一個聚集索引。

無論如何,由於主題ID沒有限制(可以添加任意數量的主題)我想嘗試在主題ID的模函數上對此表進行分區。因此,像:

topic_id % 4 == 0 => partition 0 
topic_id % 4 == 1 => partition 1 
topic_id % 4 == 2 => partition 2 
topic_id % 4 == 3 => partition 3 

不過,我還沒有看到任何方式告訴「創建分區函數」或「創建分區方案」上的分區決定何時執行此操作。

這甚至可能嗎?我們如何根據對輸入值執行的操作來創建分區功能?

+1

「在這個表上的查詢將永遠是按主題ID,所以(id,topic_id)上有一個聚集索引。「 (topic_id,id)上的聚集索引不會更有意義嗎? –

+0

嗨馬克,對不起,確實索引是(ID,topic_id) – rusty

回答

4

您只需要將您的模數列創建爲PERSISTED計算列。

藍彼得風格,這裏有一個我早些時候發表的(雖然我敢肯定不是100%我有權分割值子句):

CREATE PARTITION FUNCTION [PF_PartitonFour] (int) 
AS RANGE RIGHT 
FOR VALUES (
    0, 
    1, 
    2) 
GO 

CREATE PARTITION SCHEME [PS_PartitionFourScheme] 
AS PARTITION [PF_PartitonFour] 
TO ([TestPartitionGroup1], 
    [TestPartitionGroup2], 
    [TestPartitionGroup3], 
    [TestPartitionGroup4]) 
GO 

CREATE TABLE [my_data] (
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [topic_id] [int] NULL, 
    [data_value] [decimal](19, 5) NULL 
    [PartitionElement] AS [topic_id] % 4 PERSISTED, 
) ON [PS_PartitionFourScheme] (PartitionElement); 
GO 
+1

謝謝!這正是我所期待的。 – rusty

+0

技術上正確,但是這不會錯過OP的問題(表現)的重點? – onupdatecascade

+3

不,它只是回答被問到的問題,而不是*我認爲應該被問到的問題。此外,有人從谷歌找到這個問題不會想要找到一個講道負荷,他們會想要找到如何根據模數函數對錶格進行分區,如果我錯了,糾正我是我給出的答案。 –

0

從文檔,好像你必須給值的函數:

要創建4個分區...

CREATE PARTITION FUNCTION myRangePF1 (int) 
AS RANGE LEFT FOR VALUES (1, 100, 1000); 

你不能只是做你的計算,這上面的電話和找到合適的值來分割?將這些值代入呼叫?或者我想念你爲什麼要使用模數?根據您的ID存在差距的可能性,您可能需要使用一些統計數據來確定分區的位置。

CREATE PARTITION FUNCTION myRangePF1 (int) 
AS RANGE LEFT FOR VALUES (@low, @Med, @High); 
3

散列分區在SQL Server 2005/2008中不可用。您必須使用範圍分區。

話雖這麼說,你應該知道,分區主要是一個存儲選項,看到Partitioned Table and Index Concepts

Partitioning makes large tables or indexes more manageable, because partitioning enables you to manage and access subsets of data quickly and efficiently, while maintaining the integrity of a data collection. By using partitioning, an operation such as loading data from an OLTP to an OLAP system takes only seconds, instead of the minutes and hours the operation takes in earlier versions of SQL Server. Maintenance operations that are performed on subsets of data are also performed more efficiently because these operations target only the data that is required, instead of the whole table.

正如你所看到的,在MSDN引進分區的重點放在維護,可管理性和數據負載。根據我的經驗,分區最多隻能提供0的性能增益。特別是在SQL 2005中。Usualy會導致性能下降。爲了提高性能,您應該使用正確的聚簇索引和正確設計的非聚簇索引。

在SQL 2008中,如果從IO角度正確分配分區,並行運算符在分區方面有所改進,請參見Designing Partitions to Improve Query Performance。儘管它們的好處是微不足道的,並且被恰當設計的集羣索引和非集羣索引集的好處掩蓋了。以(id,topic_id)中的聚集索引爲例,其中,id是身份,僅用於通過id查找單個項目。另一方面,通過(topic_id,id)的聚集索引將有利於查找特定主題的任何查詢。我不知道你的系統需求和你運行的查詢,但是在這樣一個狹窄的表上有10M行的性能問題,就像索引和查詢問題,沒有分區問題。

+0

謝謝!將索引從(id,topic_id)更改爲(topic_id,id)顯着加快了查詢速度。我希望我能在這裏給出兩個接受的答案,但馬特的回答正是我所期待的。 – rusty

0

1000萬行對於SQL服務器來說並不是那麼多;常規索引設計可能會解決這個問題,而不需要分區。如前所述,請嘗試對不同的列集合進行聚類;聚集在topicid上,id似乎是要測試的東西,特別是如果大多數查詢都有topicid作爲標準。像這樣的聚集索引與分區效果大致相同,至少它將相關的數據行集中在磁盤上,並允許範圍掃描快速獲取它們。

如果這種設計有效,所有你必須擔心的是插入的碎片,但這是可管理的。獲得索引權後,確保您有足夠的內存,並且沒有磁盤瓶頸。