什麼是表分區
SQL Server使用三種不同類型的文件存儲數據,它們分別是.mdf、.ndf和.ldf。主要數據存儲在
.mdf文件中,比如表,索引,存儲過程等。.ndf文件也用於儲存這些數據。.ldf文件用於存儲操作日誌。
表默認存儲在.mdf文件中。更新表時SQL Server會對錶鎖。那麼其它的操作必須等待正在更新操作完成。
如果一個表很大,那麼無論是查詢操作還是更新操作,性能都會很差。如果將表分別存儲在物理上獨立但邏輯上連續的
分區中,那麼SQL Server可以大幅優化查詢操作和更新操作的性能。
分區的優點
1、提高可伸縮性和可管理性:在SQL Server 2005中建立分區,改善大型表以及具有各種訪問模式的表的可伸縮性和可管理性。
2、提高性能
3、只有將數據分區分到不同的磁盤上,纔會有較大的提升。
4、因爲在運行涉及表間聯接的查詢時,多個磁頭可以同時讀取數據。
分區時需注意事項
1、雖然分區可以帶來衆多的好處,但是同時也增加了實現對象的管理費用和複雜性。因此在進行分區之前要首先仔細的考慮以確定是否應爲對象進行分區。
2、在確定了爲對象進行分區後,下一步就要確定分區鍵和分區數。要確定分區數據,應先評估您的數據中是否存在邏輯分組和模式。
3、確定是否應使用多個文件分組。爲了有助於優化性能和維護,應使用文件組分離數據。文件組是數據庫數據文件的邏輯組合,它可以對數據文件進行管理和分配,以便提高數據庫文件的併發訪問效率。
分區的實現
alter database <數據庫名> add filegroup <文件組名>
2.創建數據文件到文件組:
alter database <數據庫名稱> add file <數據標識> to filegroup <文件組名稱> --<數據標識> (name:文件名,fliename:物理路徑文件名,size:文件初始大小kb/mb/gb/tb,filegrowth:文件自動增量kb/mb/gb/tb/%,maxsize:文件可以增加到的最大大小kb/mb/gb/tb/unlimited)
3.右鍵要分區的表,存儲選項中創建分區
4.打開創建分區嚮導,下一步
5.選擇列後下一步,新建分區函數,寫入函數名稱,下一步
6.新建分區方案,寫入方案名稱
7.創建分區規則
左邊界右邊界:就是把臨界值劃分給上一個分區還是下一個分區。一個小於號,一個小於等於號。
8.下一步,得到分區語句 及 方案,執行後,分區完成。
SQL語句實現
1.分區函數
指定分依據區列(依據列唯一),分區數據範圍規則,分區數量,然後將數據映射到一組分區上。
創建語法:
create partition function 分區函數名(<分區列類型>) as range [left/right] for values (每個分區的邊界值,....)
然而,分區函數只定義了分區的方法,此方法具體用在哪個表的那一列上,則需要在創建表或索引是指定。
刪除語法:
--刪除分區語法 drop partition function <分區函數名>
需要注意的是,只有沒有應用到分區方案中的分區函數才能被刪除。
2.分區方案
指定分區對應的文件組。
創建語法:
--創建分區方案語法 create partition scheme <分區方案名稱> as partition <分區函數名稱> [all]to (文件組名稱,....)
分區函數必須關聯分區方案纔能有效,然而分區方案指定的文件組數量必須與分區數量一致,哪怕多個分區存放在一個文件組中。
刪除語法:
--刪除分區方案語法 drop partition scheme<分區方案名稱>
只有沒有分區表,或索引使用該分區方案是,才能對其刪除。
3.分區表
創建語法:
--創建分區表語法 create table <表名> ( <列定義> )on<分區方案名>(分區列名)
如果在表中創建主鍵或唯一索引,則分區依據列必須爲該列。
4.分區索引
創建語法:
--創建分區索引語法 create <索引分類> index <索引名稱> on <表名>(列名) on <分區方案名>(分區依據列名)
使用分區索引查詢,可以避免多個cpu操作多個磁盤時產生的衝突。
執行完成後,右鍵要分區的表,選擇現有的分區函數、分區方案。
分區表明細信息
1.查看分區依據列的指定值所在的分區
--查詢分區依據列爲10000014的數據在哪個分區上 select $partition.分區函數名稱(2000000) --返回值是2,表示此值存在第2個分區
2.查看分區表中,每個非空分區存在的行數
--查看分區表中,每個非空分區存在的行數 select $partition.分區函數名稱(列名稱) as partitionNum,count(*) as recordCount from 表名 group by $partition.分區函數名稱(列名稱)
3.查看指定分區中的數據記錄
---查看指定分區中的數據記錄 select * from 表名 where $partition.分區函數名稱(列名稱)=2
結果:數據從1000001開始到200W結束
分區的拆分及合併與數據移動
1.拆分分區
在分區函數中新增一個邊界值,即可將一個分區變爲2個。
--分區拆分 alter partition function 分區函數名稱() split range(N'1500000') --將第二個分區拆爲2個分區
注意:如果分區函數已經指定了分區方案,則分區數需要和分區方案中指定的文件組個數保持對應一致。
2.合併分區
與拆分分區相反,去除一個邊界值即可。
--合併分區 alter partition function 分區函數名稱() merge range(N'1500000') --將第二第三分區合併
3.分區中的數據移動
你或許會遇到這樣的需求,將普通表數據複製到分區表中,或者將分區表中的數據複製到普通表中。
那麼移動數據這兩個表,則必須滿足下面的要求。
- 字段數量相同,對應位置的字段相同
- 相同位置的字段要有相同的屬性,相同的類型。
- 兩個表在一個文件組中
1.創建表時指定文件組
--創建表 create table <表名> ( <列定義> )on <文件組名>
2.從分區表中複製數據到普通表
--將bigorder分區表中的第一分區數據複製到普通表中 alter table 表名 switch partition 1 to <普通表名>
3.從普通標中複製數據到分區表中
這裏要注意的是要先將分區表中的索引刪除,即便普通表中存在跟分區表中相同的索引。
--將普通表中的數據複製到bigorder分區表中的第一分區 alter table <普通表名> switch to 表名 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