大凡在應用系統和數據庫系統中行走江湖多年的朋友,都會面臨數據統計、分析以及歸檔的問題,企業信息化進程加速了各種數據的極具增長,商務智能(BI)的出現和實施着實給信息工作者和決策者帶來了絕妙的體驗,但從 OLTP 向 OLAP 系統加載數據是很頭疼的事,常常需要數分鍾或數小時,解 決這一問題的技術之一便是分區表,一旦實施了分區表,這樣的操作往往只需幾秒鍾,太讓人興奮了。而大型表或索引經過分區后更容易進行管理,因為這樣可以快 速高效地管理和訪問數據子集,同時維護數據集合的完整性。分區表的數據分布於一個數據庫中的多個文件組單元中,數據是按水平方式分區的(數據分區的多種方 式會在分區表前傳中闡述),因此一個表的某些行映射到某個分區,而另外一些行映射到另外某個分區,以此類推。當對數據進行查詢或更新時,表將被視為單個邏 輯實體,所以在數據訪問層你會感覺和訪問普通表一樣,而好處就在於可以查詢想要的某個分區,而不必掃描整個表。有一點必須明白,單個表的所有分區都必須位 於同一個數據庫中。
分區表支持和標准表相關的所有屬性和功能,包括約束、默認值、標識和時間戳值以及觸發器等。決定是否實現分區主要取決於表當前的大小或將來的大小以及對表執行查詢和維護操作的完善程度。
通常,如果某個大型表同時滿足下列兩個條件,則可能適於進行分區:
1,該表包含或將包含以多種不同方式使用的大量數據
2,維護開銷超過了預定義的維護期
例如,如果對當前年份或當前月份的數據主要執行 SELECT 、INSERT、UPDATE 和 DELETE 操作,而對以前年份或以前月份的數據主要執行 SELECT 查詢,則如果按年份或月份對表進行分區,表的管理要容易些,因為此時對表的維護操作只針對一個數據子集。如果該表沒有分區,那么就需要對整個數據集執行這些操作,這樣就會消耗大量資源。
所以常常根據日期和分類對表進行分區,當然利用某個標識列ID也是很好的選擇。例如,電子商務數據庫的某張表可能包含了近6年的數據,但是只定期訪問本年度或某個月的數據,那么就可以按年份或月份分區,而另外一張表包含了近幾十種類型商品的訂單,那么此時可以為每種類型商品分一個區。
一般而言,衡量大型表是以數據為標准的,但對於適合分區的大型表,衡量大型表更重要的是對數據訪問的性能,如果對於某些表的訪問和維護有較嚴重的性能問題,就可以視為大型表,就應該考慮通過更好的設計和分區來解決性能問題。
創建分區表必須經過如下三個步驟:
1, 創建分區函數
2, 創建映射到分區函數的分區方案
3, 創建使用該分區方案的分區表
分區函數
分區函數是數據庫中的一個獨立對象,它將表的行映射到一組分區,所以分區函數解決的是HOW的問題,即表如何分區的問題。創建分區函數時,必須指明數據分區的邊界點以及分區依據列,這樣便知道如何對表或索引進行分區。分區函數的創建語法如下:
CREATE PARTITION FUNCTION partition_function_name ( input_parameter_type )
AS RANGE [ LEFT | RIGHT ]
FOR VALUES ( [ boundary_value [ ,...n ] ] )
[ ; ]
分區函數語法的相關解釋:
1, 創建一個分區函數和創建一個普通的數據庫對象(例如表)沒什么區別。所以根據標准語法走就OK了。
2, partition_function_name是分區函數的名稱。分區函數名稱在數據庫內必須唯一,並且符合標識符的規則。
3, input_parameter_type是用於分區的列的數據類型,習慣把它稱為分區依據列。當用作分區列時,除 text、ntext、image、xml、timestamp、varchar(max)、nvarchar(max)、varbinary(max)、別名數據類型或 CLR 用戶定義數據類型外,其他所有數據類型均有效。分區依據列是在 CREATE TABLE 或 CREATE INDEX 語句中指定的。
4, boundary_value [ ,...n ]中的boundary_value是邊界值(或邊界點的值),n代表可以最多有n個邊界值,即n指定 boundary_value 提供的值的數目,但n不能超過 999。所創建的分區數等於 n + 1。不必按順序列出各值。如果值未按順序列出,則 Database Engine 將對這些邊界值進行排序,創建分區函數並返回一個警告,說明未按順序提供值。如果 n 包括任何重復的值,則數據庫引擎將返回錯誤。邊界值的取值一定是和分區依據列相關的,所以只能使用 CREATE TABLE 或 CREATE INDEX 語句中指定的一個分區列。
5, LEFT | RIGHT 指定boundary_value [ ,...n ] 的每個boundary_value屬於每個邊界值間隔的哪一側(左側還是右側)。如果未指定,則默認值為 LEFT。
例如我們可以依據某個表的int列來創建分區函數:
create partition function MyPF1(int)
range left --默認是left,所以可以省略left
for values(500000,1000000,1500000)
很明顯,這個分區函數創建了4個分區,因為此時n=3,所以分區總數是n+1=4。而那個int分區依據列表明將要分區的那個表里面一定有一列是int類型,是分區依據列。這個分區函數我們用的是range left,各個分區的取值范圍如下表:
分區
|
取值范圍
|
1
|
(負無窮,500000]
|
2
|
[500001,1000000]
|
3
|
[1000001,1500000]
|
4
|
[1500001,正無窮)
|
如果換成range right,即創建分區函數時代碼如下:
create partition function MyPF1(int)
range right
for values(500000,1000000,1500000)
那么各個分區的取值范圍如下表:
分區
|
取值范圍
|
1
|
(負無窮,499999]
|
2
|
[500000,999999]
|
3
|
[1000000,1499999]
|
4
|
[1500000,正無窮)
|
我們還可以根據日期列創建分區函數,例如:
create partition function MyPF2(datetime)
range right
for values('2008/01/01', '2009/01/01')
這個分區函數非常適合查詢和歸檔某一年的數據。各個分區的取值范圍如下表:
分區
|
取值范圍
|
1
|
<=2007/12/31
|
2
|
[2008/01/01,2008/12/31]
|
3
|
>=2009/01/01
|
當然我們也可以根據月份分區,而分區依據列支持的數據類型非常多,參照項目的實際情況選擇最能表示分區的列類型。
分區方案
對表和索引進行分區的第二步是創建分區方案。分區方案定義了一個特定的分區函數將使用的物理存儲結構(其實就是文件組),或者說是分區方案將分區函數生成的分區映射到我們定義的一組文件組。所以分區方案解決的是Where的問題,即表的各個分區在哪里存儲的問題。分區方案的創建語法如下:
CREATE PARTITION SCHEME partition_scheme_name
AS PARTITION partition_function_name
[ ALL ] TO ( { file_group_name | [ PRIMARY ] } [ ,...n ] )
[ ; ]
分區方案語法的相關解釋:
1, 創建分區方案時,根據分區函數的參數,定義映射表分區的文件組。必須指定足夠的文件組來容納分區數。可以指定所有分區映射到不同文件組、某些分區映射到單個文件組或所有分區映射到單個文件組。如果您希望在以后添加更多分區,還可以指定其他“未分配的”文件組。在這種情況下,SQL Server 用 NEXT USED 屬性標記其中一個文件組。這意味着該文件組將包含下一個添加的分區。一個分區方案僅可以使用一個分區函數。但是,一個分區函數可以參與多個分區方案。
2, partition_scheme_name 是分區方案的名稱。分區方案名稱在數據庫中必須是唯一的,並且符合標識符規則。
3, partition_function_name 是使用當前分區方案的分區函數的名稱。分區函數所創建的分區將映射到在分區方案中指定的文件組。partition_function_name 必須已經存在於數據庫中。
4, ALL 指定所有分區都映射到在 file_group_name 中提供的同一個文件組,或映射到主文件組(如果指定了 [PRIMARY])。如果指定了 ALL,則只能指定一個 file_group_name。
5, file_group_name | [ PRIMARY ] [ ,...n] 代表n個文件組。和分區函數中的各個分區對應。文件組必須已經存在於數據庫中。 如果指定了 [PRIMARY],則分區將存儲於主文件組中。如果指定了 ALL,則只能指定一個 file_group_name。分區分配到文件組的順序是從分區 1 開始,按文件組在 [,...n] 中列出的順序進行分配。在 [,...n] 中,可以多次指定同一個文件組。如果 n 不足以擁有在分區函數中指定的分區數,則 CREATE PARTITION SCHEME 將失敗,並返回錯誤。
6, 如果分區函數生成的分區數少於創建分區方案時提供的文件組數,則分區方案中第一個未分配的文件組將被標記為 NEXT USED,並且出現顯示命名 NEXT USED 文件組的信息。如果指定了 ALL,則單獨的文件組將為該分區函數保持它的NEXT USED 屬性。如果在 ALTER PARTITION FUNCTION 語句中創建了一個分區,則 NEXT USED 文件組將再接收一個分區。若要再創建一個未分配的文件組來擁有新的分區,請使用 ALTER PARTITION SCHEME。
分區方案例子1:下面的代碼先創建一個分區函數,然后再創建這個分區函數使用的分區方案,這個分區方案將每個分區映射到不同文件組。代碼如下:
create partition function MyPF1(int)
as range left
for values(500000,1000000,1500000)
go
create partition scheme MyPS1
as partition MyPF1
to (fg1, fg2, fg3, fg4)
文件組、分區和分區邊界值范圍之間的關系如下表:
文件組
|
分區
|
取值范圍
|
fg1
|
1
|
(負無窮,500000]
|
fg2
|
2
|
[500001,1000000]
|
fg3
|
3
|
[1000001,1500000]
|
fg4
|
4
|
[1500001,正無窮)
|
分區方案例子2:下面的代碼先創建一個分區函數,然后再創建這個分區函數使用的分區方案,這個分區方案將多個分區映射到同一個文件組。代碼如下:
create partition function MyPF2(int)
as range left
for values(500000,1000000,1500000)
go
create partition scheme MyPS2
as partition MyPF2
to (fg1, fg1, fg1, fg2)
文件組、分區和分區邊界值范圍之間的關系如下表:
文件組
|
分區
|
取值范圍
|
fg1
|
1
|
(負無窮,500000]
|
Fg1
|
2
|
[500001,1000000]
|
Fg1
|
3
|
[1000001,1500000]
|
Fg2
|
4
|
[1500001,正無窮)
|
分區方案例子3:下面的代碼先創建一個分區函數,然后再創建這個分區函數使用的分區方案,這個分區方案將所有分區映射到同一個文件組。代碼如下:
create partition function MyPF3 (int)
as range left
for values(500000,1000000,1500000)
go
create partition scheme MyPS3
as partition MyPF3
all to (fg1)
文件組、分區和分區邊界值范圍之間的關系如下表:
文件組
|
分區
|
取值范圍
|
fg1
|
1
|
(負無窮,500000]
|
Fg1
|
2
|
[500001,1000000]
|
Fg1
|
3
|
[1000001,1500000]
|
Fg1
|
4
|
[1500001,正無窮)
|
分區方案例子4:下面的代碼先創建一個分區函數,然后再創建這個分區函數使用的分區方案,這個分區方案指定了“NEXT USED”文件組。代碼如下:
create partition function MyPF4(int)
as range left
for values(500000,1000000,1500000) --4個分區
go
create partition scheme MyPS4
as partition MyPF4
to (fg1, fg2, fg3, fg4, fg5) --5個文件組
那么文件組fg5將自動被標記為“NEXT USED”文件組。
分區方案例子5:下面的代碼先創建一個分區函數,然后再創建這個分區函數使用的分區方案,這個分區方案指定了“[primary]”文件組。代碼如下:
create partition function MyPF5(datetime)
range right
for values('2008/01/01', '2009/01/01')
go
create partition scheme MyPS5
as partition MyPF5
to([primary], fg1, fg2)
最后必須明白一點,一張表最多只能有1000個分區。
分區表
在分區函數和分區方案創建完成后,創建分區表的准備工作已經完成。我們看一個完整的例子,代碼如下:
--創建分區函數
create partition function MyPF(datetime)
range right
for values('2007-1-1', '2008-1-1')
go
--創建分區方案
create partition scheme MyPS
as partition MyPF
to(fg1, fg2, fg3)
go
--創建分區表
create table orders
(
OrderID int identity(1,1) primary key,
OrderDate datetime,
CustID varchar(10)
)
on MyPS(OrderDate)
原文轉載:http://blog.csdn.net/pt1314917/article/details/4435083