正如上一篇文章SqlServer性能優化——Partition(創建分區)中所述,分區並不是一個一勞永逸的操作,對一張表做好分區僅僅是開始,接下來可能需要頻繁的變更分區,管理分區。
在企業管理器中,雖然有“管理分區”的菜單,裡面的內容卻可能與你的預想不同,這裡並沒有提供直接對分區進行操作的方法,所以一些普通的操作,比如“增加分區”、“刪除分區”之類的操作就需要通過腳本實現了。
增加分區(Split Partition)
“增加分區”事實上就是將現有的分區分割開,基於此,在SQL Server中應用的是Split操作。在分離分區的時候,不僅僅要在Partition Function上指定分割的分界點,同樣需要在Partition Scheme上指定新分區應用的文件組:
--指定下一個分區應用文件組PRIMARY
ALTER PARTITION SCHEME [MyPartitionSchema]
NEXT USED [PRIMARY]
--指定分區分界點為5000
ALTER PARTITION FUNCTION MyPartitionFunction()
SPLIT RANGE (5000)
需要注意的一點是,新增的分區中非聚簇索引的壓縮模式會被置為None。
刪除分區(Merge Partition)
“刪除分區”同樣可以認為是將原來分離的分區合並在一起,所以對應的是Merge操作,而且由於並沒有新增的分區,Partition Scheme並不需要改變:
ALTER PARTITION FUNCTION MyPartitionFunction ()
MERGE RANGE (5000)
切換分區(Switch Partition)
“切換分區”可能是一個比看上去會應用的更頻繁的操作,它的意義在於將一個分區的數據從一張表切換到另一張表中。這裡定義被切換分區的表為“源表”,被切換到的表為“目標表”,則執行切換操作的前提是:
源表和目標表擁有同樣的表結構,即同樣的字段、字段類型,同樣的索引結構(聚簇和非聚簇),同樣的壓縮格式。但不要求默認值約束一致(Default Constaint),也不要求目標表設置了和源表一樣的自增長列。
源表如果有索引且分區,則其索引必須對齊。
源表中被切換的分區范圍必須包含於目標表或者目標表將要被切換到的分區范圍。這裡有如下幾種情況:
將源表的源分區切換到目標表的目標分區中,則目標分區范圍>=源分區;
將源表的源分區切換到目標表中(目標表未分區),則目標表沒有設約束,或約束范圍>=源分區;
將源表切換到目標表中(源表、目標表都未分區),則只要目標表沒有設約束就可以了(雖然Switch是分區提出的操作,但一個沒有分區的表同樣可以被看做一個大分區,所以可以對沒有分區的表進行Switch操作)。
目標表或目標分區不能含有數據。
下面的操作將源表的第二個分區切換到目標表的第二個分區中。
ALTER TABLE [STable] SWITCH PARTITION 2 TO [DTable] PARTITION 2
分區管理操作的性能
分割、合並以及切換分區是元數據上的操作而不是對數據的移動,所以操作的效率要比直接操作數據高很多。
對於分割分區,操作時間和被分割分區的數據量相關,數據越大則分割花費的時間會越長。
對於合並分區,如果將兩個空的分區合並,自然不會耗什麼時間;如果兩個分區都有數據,則和分割分區一樣,數據越大花費的時間越長;如果兩個分區中有一個沒有數據,筆者的經驗是如果有大數據量的分區在右(>分界值),則消耗的時間較短,如果有大數據量的分區在左(<分界值),則會消耗較多的時間。
對於切換分區,即使是上千萬級別的數據,也可以在不到1秒的時間完成分區的切換。所以雖然從表面上看,切換分區和調用Select或者Insert語句移動數據的結果是一樣的,但效率卻是不可同日而語的。
查看分區信息
除了利用上文提到的通過“管理壓縮”的方式查看某張表的分區信息之外,SQL Server還提供了一張系統表查看數據庫中的分區情況:
SYS.PARTITION_SCHEMES,數據庫中所有分區方案的信息,包括對應的分區函數的ID。
SYS.PARTITION_FUNCTIONS,數據庫中所有分區函數的信息,包括分區數等信息。
SYS.PARTITION_RANGE_VALUES,每個分區范圍的信息,可以和SYS.PARTITION_FUNCTIONS聯查。
比如可以通過如下的腳本,查出分區函數MyPartitionFunc的第一個分區的右邊界:
SELECT value FROM sys.partition_range_values, sys.partition_functions
WHERE sys.partition_functions.function_id = sys.partition_range_values.function_id
AND sys.partition_functions.name = 'MyPartitionFunc' AND boundary_id = 1
還可以通過如下腳本,獲取分區表中各分區的數據情況(行數,最大值,最小值):
SELECT
partition = $PARTITION.MyParitionFunc([ParitionDate])
,rows = COUNT(*)
,min = MIN([ParitionDate])
,max = MAX([ParitionDate])
FROM [MyTable]
GROUP BY $PARTITION.MyParitionFunc([ParitionDate])
ORDER BY PARTITION
具體可以參照MSDN:從已分區表和索引中查詢數據和元數據