SQL Server表分割槽
什麼是表分割槽
一般情況下,我們建立資料庫表時,表資料都存放在一個檔案裡。
但是如果是分割槽表的話,表資料就會按照你指定的規則分放到不同的檔案裡,把一個大的資料檔案拆分為多個小檔案,還可以把這些小檔案放在不同的磁碟下由多個cpu進行處理。這樣檔案的大小隨著拆分而減小,還得到硬體系統的加強,自然對我們操作資料是大大有利的。
所以大資料量的資料表,對分割槽的需要還是必要的,因為它可以提高select效率,還可以對歷史資料經行區分存檔等。但是資料量少的資料就不要湊這個熱鬧啦,因為表分割槽會對資料庫產生不必要的開銷,除啦效能還會增加實現物件的管理費用和複雜性。
跟著做,分割槽如此簡單
先跟著做一個分割槽表(分為11個分割槽),去除神祕的面紗,然後咱們再逐一擊破各個要點要害。
分割槽是要把一個表資料拆分為若干子集合,也就是把把一個數據檔案拆分到多個數據檔案中,然而這些檔案的存放可以依託一個檔案組或這多個檔案組,由於多個檔案組可以提高資料庫的訪問併發量,還可以把不同的分割槽配置到不同的磁碟中提高效率,所以建立時建議分割槽跟檔案組個數相同。
1.建立檔案組
可以點選資料庫屬性在檔案組裡面新增
T-sql語法:
alter database <資料庫名> add filegroup <檔案組名> ---建立資料庫檔案組 alter database testSplit add filegroup ByIdGroup1 alter database testSplit add filegroup ByIdGroup2 alter database testSplit add filegroup ByIdGroup3 alter database testSplit add filegroup ByIdGroup4 alter database testSplit add filegroup ByIdGroup5 alter database testSplit add filegroup ByIdGroup6 alter database testSplit add filegroup ByIdGroup7 alter database testSplit add filegroup ByIdGroup8 alter database testSplit add filegroup ByIdGroup9 alter database testSplit add filegroup ByIdGroup10
2.建立資料檔案到檔案組裡面
可以點選資料庫屬性在檔案裡面新增
T-sql語法:
alter database <資料庫名稱> add file <資料標識> to filegroup <檔案組名稱> --<資料標識> (name:檔名,fliename:物理路徑檔名,size:檔案初始大小kb/mb/gb/tb,filegrowth:檔案自動增量kb/mb/gb/tb/%,maxsize:檔案可以增加到的最大大小kb/mb/gb/tb/unlimited) alter database testSplit add file (name=N'ById1',filename=N'J:\Work\資料庫\data\ById1.ndf',size=5Mb,filegrowth=5mb) to filegroup ByIdGroup1 alter database testSplit add file (name=N'ById2',filename=N'J:\Work\資料庫\data\ById2.ndf',size=5Mb,filegrowth=5mb) to filegroup ByIdGroup2 alter database testSplit add file (name=N'ById3',filename=N'J:\Work\資料庫\data\ById3.ndf',size=5Mb,filegrowth=5mb) to filegroup ByIdGroup3 alter database testSplit add file (name=N'ById4',filename=N'J:\Work\資料庫\data\ById4.ndf',size=5Mb,filegrowth=5mb) to filegroup ByIdGroup4 alter database testSplit add file (name=N'ById5',filename=N'J:\Work\資料庫\data\ById5.ndf',size=5Mb,filegrowth=5mb) to filegroup ByIdGroup5 alter database testSplit add file (name=N'ById6',filename=N'J:\Work\資料庫\data\ById6.ndf',size=5Mb,filegrowth=5mb) to filegroup ByIdGroup6 alter database testSplit add file (name=N'ById7',filename=N'J:\Work\資料庫\data\ById7.ndf',size=5Mb,filegrowth=5mb) to filegroup ByIdGroup7 alter database testSplit add file (name=N'ById8',filename=N'J:\Work\資料庫\data\ById8.ndf',size=5Mb,filegrowth=5mb) to filegroup ByIdGroup8 alter database testSplit add file (name=N'ById9',filename=N'J:\Work\資料庫\data\ById9.ndf',size=5Mb,filegrowth=5mb) to filegroup ByIdGroup9 alter database testSplit add file (name=N'ById10',filename=N'J:\Work\資料庫\data\ById10.ndf',size=5Mb,filegrowth=5mb) to filegroup ByIdGroup10
執行完成後,右鍵資料庫看檔案組跟檔案裡面是不是多出來啦這些檔案組跟檔案。
3.使用嚮導建立分割槽表
右鍵到要分割槽的表--- >> 儲存 --- >> 建立分割槽 --- >>顯示嚮導檢視 --- >> 下一步 --- >> 下一步。。
這裡舉例說下選擇列的意思:
假如你選擇的是int型別的列:那麼你的分割槽可以指定為1--100W是一個分割槽,100W--200W是一個分割槽....
假如你選擇的是datatime型別:那麼你的分割槽可以指定為:2014-01-01--2014-01-31一個分割槽,2014-02-01--2014-02-28一個分割槽...
根據這樣的列資料規則劃分,那麼在那個區間的資料,在插入資料庫時就被指向那個分割槽儲存下來。
我這裡選用orderid int型別 --- >> 下一步 --- >>
左邊界右邊界:就是把臨界值劃分給上一個分割槽還是下一個分割槽。一個小於號,一個小於等於號。
然後下一步下一步最後你會得到分割槽函式和分割槽方案。
USE [testSplit]
GO
BEGIN TRANSACTION
--建立分割槽函式
CREATE PARTITION FUNCTION [bgPartitionFun](int) AS RANGE LEFT FOR VALUES (N'1000000', N'2000000', N'3000000', N'4000000', N'5000000', N'6000000', N'7000000', N'8000000', N'9000000', N'10000000')
--建立分割槽方案
CREATE PARTITION SCHEME [bgPartitionSchema] AS PARTITION [bgPartitionFun] TO ([PRIMARY], [ByIdGroup1], [ByIdGroup2], [ByIdGroup3], [ByIdGroup4], [ByIdGroup5], [ByIdGroup6], [ByIdGroup7], [ByIdGroup8], [ByIdGroup9], [ByIdGroup10])
--建立分割槽索引
CREATE CLUSTERED INDEX [ClusteredIndex_on_bgPartitionSchema_635342971076448165] ON [dbo].[BigOrder]
(
[OrderId]
)WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [bgPartitionSchema]([OrderId])
--刪除分割槽索引
DROP INDEX [ClusteredIndex_on_bgPartitionSchema_635342971076448165] ON [dbo].[BigOrder] WITH ( ONLINE = OFF )
COMMIT TRANSACTION
執行上面嚮導生成的語句。分割槽完成。。
4.秀一下速度。
首先我在表中插入啦1千萬行資料。給表分啦11個分割槽。前十個分割槽裡面一個是100W條資料。。
說兩句:
可見反常現象,掃描次數跟邏輯讀取次數都是無分割槽表的2倍之多,但查詢速度卻是快啦不少啊。這就是分割槽的神奇之處啊,所以要相信這世界一切皆有可能。
分割槽函式,分割槽方案,分割槽表,分割槽索引
1.分割槽函式
指定分依據區列(依據列唯一),分割槽資料範圍規則,分割槽數量,然後將資料對映到一組分割槽上。
建立語法:
create partition function 分割槽函式名(<分割槽列型別>) as range [left/right]
for values (每個分割槽的邊界值,....)
--建立分割槽函式
CREATE PARTITION FUNCTION [bgPartitionFun](int) AS RANGE LEFT FOR VALUES (N'1000000', N'2000000', N'3000000', N'4000000', N'5000000', N'6000000', N'7000000', N'8000000', N'9000000', N'10000000')
然而,分割槽函式只定義了分割槽的方法,此方法具體用在哪個表的那一列上,則需要在建立表或索引是指定。
刪除語法:
--刪除分割槽語法
drop partition function <分割槽函式名>
--刪除分割槽函式 bgPartitionFun
drop partition function bgPartitionFun
需要注意的是,只有沒有應用到分割槽方案中的分割槽函式才能被刪除。
2.分割槽方案
指定分割槽對應的檔案組。
建立語法:
--建立分割槽方案語法
create partition scheme <分割槽方案名稱> as partition <分割槽函式名稱> [all]to (檔案組名稱,....)
--建立分割槽方案,所有分割槽在一個組裡面
CREATE PARTITION SCHEME [bgPartitionSchema] AS PARTITION [bgPartitionFun] TO ([ByIdGroup1], [ByIdGroup1], [ByIdGroup1], [ByIdGroup1], [ByIdGroup1], [ByIdGroup1], [ByIdGroup1], [ByIdGroup1], [ByIdGroup1], [ByIdGroup1], [ByIdGroup1])
分割槽函式必須關聯分割槽方案才能有效,然而分割槽方案指定的檔案組數量必須與分割槽數量一致,哪怕多個分割槽存放在一個檔案組中。
刪除語法:
--刪除分割槽方案語法
drop partition scheme<分割槽方案名稱>
--刪除分割槽方案 bgPartitionSchema
drop partition scheme bgPartitionSchema1
只有沒有分割槽表,或索引使用該分割槽方案是,才能對其刪除。
3.分割槽表
建立語法:
--建立分割槽表語法
create table <表名> (
<列定義>
)on<分割槽方案名>(分割槽列名)
--建立分割槽表
create table BigOrder (
OrderId int identity,
orderNum varchar(30) not null,
OrderStatus int not null default 0,
OrderPayStatus int not null default 0,
UserId varchar(40) not null,
CreateDate datetime null default getdate(),
Mark nvarchar(300) null
)on bgPartitionSchema(OrderId)
如果在表中建立主鍵或唯一索引,則分割槽依據列必須為該列。
4.分割槽索引
建立語法:
--建立分割槽索引語法
create <索引分類> index <索引名稱>
on <表名>(列名)
on <分割槽方案名>(分割槽依據列名)
--建立分割槽索引
CREATE CLUSTERED INDEX [ClusteredIndex_on_bgPartitionSchema_635342971076448165] ON [dbo].[BigOrder]
(
[OrderId]
)WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [bgPartitionSchema]([OrderId])
使用分割槽索引查詢,可以避免多個cpu操作多個磁碟時產生的衝突。
分割槽表明細資訊
這裡的語法,我就不寫啦,自己看語句分析吧。簡單的很。。
1.檢視分割槽依據列的指定值所在的分割槽
--查詢分割槽依據列為10000014的資料在哪個分割槽上
select $partition.bgPartitionFun(2000000) --返回值是2,表示此值存在第2個分割槽
2.檢視分割槽表中,每個非空分割槽存在的行數
--檢視分割槽表中,每個非空分割槽存在的行數
select $partition.bgPartitionFun(orderid) as partitionNum,count(*) as recordCount
from bigorder
group by $partition.bgPartitionFun(orderid)
3.檢視指定分割槽中的資料記錄
---檢視指定分割槽中的資料記錄
select * from bigorder where $partition.bgPartitionFun(orderid)=2
結果:資料從1000001開始到200W結束
分割槽的拆分與合併以及資料移動
1.拆分分割槽
在分割槽函式中新增一個邊界值,即可將一個分割槽變為2個。
--分割槽拆分
alter partition function bgPartitionFun()
split range(N'1500000') --將第二個分割槽拆為2個分割槽
注意:如果分割槽函式已經指定了分割槽方案,則分割槽數需要和分割槽方案中指定的檔案組個數保持對應一致。
2.合併分割槽
與拆分分割槽相反,去除一個邊界值即可。
--合併分割槽
alter partition function bgPartitionFun()
merge range(N'1500000') --將第二第三分割槽合併
3.分割槽中的資料移動
你或許會遇到這樣的需求,將普通表資料複製到分割槽表中,或者將分割槽表中的資料複製到普通表中。
那麼移動資料這兩個表,則必須滿足下面的要求。
- 欄位數量相同,對應位置的欄位相同
- 相同位置的欄位要有相同的屬性,相同的型別。
- 兩個表在一個檔案組中
1.建立表時指定檔案組
--建立表
create table <表名> (
<列定義>
)on <檔案組名>
2.從分割槽表中複製資料到普通表
--將bigorder分割槽表中的第一分割槽資料複製到普通表中
alter table bigorder switch partition 1 to <普通表名>
3.從普通標中複製資料到分割槽表中
這裡要注意的是要先將分割槽表中的索引刪除,即便普通表中存在跟分割槽表中相同的索引。
--將普通表中的資料複製到bigorder分割槽表中的第一分割槽
alter table <普通表名> switch to bigorder partition 1
分割槽檢視
分割槽檢視是先建立帶有欄位約束的相同表,而約束不同,例如,第一個表的id約束為0--100W,第二表為101萬到200萬.....依次類推。
建立完一系列的表之後,用union all 連線起來建立一個檢視,這個檢視就形成啦分割槽視同。
很簡單的,這裡我主要是說分割槽表,就不說分割槽檢視啦。。
檢視資料庫分割槽資訊
SELECT OBJECT_NAME(p.object_id) AS ObjectName,
i.name AS IndexName,
p.index_id AS IndexID,
ds.name AS PartitionScheme,
p.partition_number AS PartitionNumber,
fg.name AS FileGroupName,
prv_left.value AS LowerBoundaryValue,
prv_right.value AS UpperBoundaryValue,
CASE pf.boundary_value_on_right
WHEN 1 THEN 'RIGHT'
ELSE 'LEFT' END AS Range,
p.rows AS Rows
FROM sys.partitions AS p
JOIN sys.indexes AS i
ON i.object_id = p.object_id
AND i.index_id = p.index_id
JOIN sys.data_spaces AS ds
ON ds.data_space_id = i.data_space_id
JOIN sys.partition_schemes AS ps
ON ps.data_space_id = ds.data_space_id
JOIN sys.partition_functions AS pf
ON pf.function_id = ps.function_id
JOIN sys.destination_data_spaces AS dds2
ON dds2.partition_scheme_id = ps.data_space_id
AND dds2.destination_id = p.partition_number
JOIN sys.filegroups AS fg
ON fg.data_space_id = dds2.data_space_id
LEFT JOIN sys.partition_range_values AS prv_left
ON ps.function_id = prv_left.function_id
AND prv_left.boundary_id = p.partition_number - 1
LEFT JOIN sys.partition_range_values AS prv_right
ON ps.function_id = prv_right.function_id
AND prv_right.boundary_id = p.partition_number
WHERE
OBJECTPROPERTY(p.object_id, 'ISMSShipped') = 0
UNION ALL
SELECT
OBJECT_NAME(p.object_id) AS ObjectName,
i.name AS IndexName,
p.index_id AS IndexID,
NULL AS PartitionScheme,
p.partition_number AS PartitionNumber,
fg.name AS FileGroupName,
NULL AS LowerBoundaryValue,
NULL AS UpperBoundaryValue,
NULL AS Boundary,
p.rows AS Rows
FROM sys.partitions AS p
JOIN sys.indexes AS i
ON i.object_id = p.object_id
AND i.index_id = p.index_id
JOIN sys.data_spaces AS ds
ON ds.data_space_id = i.data_space_id
JOIN sys.filegroups AS fg
ON fg.data_space_id = i.data_space_id
WHERE
OBJECTPROPERTY(p.object_id, 'ISMSShipped') = 0
ORDER BY
ObjectName,
IndexID,
PartitionNumber