/*************************************************************** BIWORK 分區表閱讀與實踐筆記 Note: 示例中使用到了SQL Server 2000的 Demo Database, 可以從此鏈接中下載 http://www.microsoft.com/en-us/download/confirmation.aspx?id=23654 在檢查刪除Partition Function 以及Partition Scheme 時,要注意 Partition Scheme 引用了Partition Function, 所有需要先刪除 Partition Scheme. 同理,引用了Partition Scheme 的表應該先刪除掉. 引用關系: TABLE -> PARTITION SCHEME -> PARTITION FUNCTION ***************************************************************/ IF OBJECT_ID('dbo.Orders')IS NOT NULL DROP TABLE Orders GO IF EXISTS (SELECT * FROM sys.partition_schemes WHERE name = 'PS_Orders') DROP PARTITION SCHEME PS_Orders GO IF EXISTS (SELECT * FROM sys.partition_functions WHERE name = 'PF_Orders_OrderDateRange') DROP PARTITION FUNCTION PF_Orders_OrderDateRange GO /*************************************************************** 1. 如果在不需要對數據庫進行物理分組的情況下,比如分區表還是享用同 一個文件組,那麼應該可以從創建分區函數開始 *** 創建分區函數 *** 確定分區鍵列的類型(DATETIME)以及分區的邊界值: (''1997-01-01','1998-01-01','1999-01-01'') *** N個邊界值確定N+1 個分區 *** RIGHT - 第一個分區的所有值都小於VAL < 1997-01-1 第二個分區的值范圍是1997-01-01 <= VAL < 1998-01-01 ***************************************************************/ CREATE PARTITION FUNCTION PF_Orders_OrderDateRange(DATETIME) AS RANGE RIGHT FOR VALUES ( '1997-01-01', '1998-01-01', '1999-01-01' ) GO EXEC dbo.sp_show_partition_range @partition_function = 'PF_Orders_OrderDateRange' /*************************************************************** 顯示分區函數的分區情況,PARTITION FUNCTION,PARTITION,MinVal,VALUE,MaxVal PF_Orders_OrderDateRange 1 NULL <= val < 1997-01-01 00:00:00.000 PF_Orders_OrderDateRange 2 1997-01-01 00:00:00.000 <= val < 1998-01-01 00:00:00.000 PF_Orders_OrderDateRange 3 1998-01-01 00:00:00.000 <= val < 1999-01-01 00:00:00.000 PF_Orders_OrderDateRange 4 1999-01-01 00:00:00.000 <= val < NULL ****************************************************************/ /*************************************************************** 2. 創建了分區函數後,便可以創建分區方案 *** 因為在上一個分區函數中有個邊界值,4個分區,並且並沒有其它的 數據庫文件組,所以當分區方案應用到具體的分區函數時所有的分區 都是指向PRIMARY 文件組 ***************************************************************/ CREATE PARTITION SCHEME PS_Orders AS PARTITION PF_Orders_OrderDateRange TO ([primary],[primary],[primary],[primary]) GO /*************************************************************** 3. 創建分區表時要應用分區方案,並提供具體的分區鍵列 ON 分區函數(分區鍵列) ****************************************************************/ CREATE TABLE dbo.Orders ( OrderID INT NOT NULL, CustomerID VARCHAR(10) NOT NULL, EmployeeID INT NOT NULL, OrderDate DATETIME NOT NULL ) ON PS_Orders(OrderDate) GO /****************************************************************** 4. 在創建分區表後,需要創建聚集分區索引 *** 根據訂單表Orders 查詢時經常使用OrderDate 范圍條件來查詢的特點, *** 我們最好在Orders.OrderDate 列上建立聚集索引(clustered index). *** 為了便於進行分區切換(partition swtich) 大多數情況下,建議在分區表上建立分區索引。 *******************************************************************/ CREATE CLUSTERED INDEX IXC_Orders_OrderDate ON dbo.Orders(OrderDate) GO /******************************************************************* 5. 為分區表創建主鍵 如果主鍵不包含分區鍵列,將會出現以下錯誤信息: Msg 1908, Level 16, State 1, Line 2 Column 'OrderDate' is partitioning column of the index 'PK_Orders'. Partition columns for a unique index must be a subset of the index key. Msg 1750, Level 16, State 0, Line 2 Could not create constraint. See previous errors. 原因: 主鍵實際上是個唯一索引,但分區表在建立唯一索引(分區索引)的時候, 分區列必須是唯一索引的一部分.因為SQL Server 不但要保證索引在各個 分區是唯一的,還要保證在整個表中是唯一的. ********************************************************************/ ALTER TABLE dbo.Orders ADD CONSTRAINT PK_Orders PRIMARY KEY(OrderID, CustomerID,OrderDate) GO /************************************************************************ 查看分區表Orders 上的索引: IXC_Orders_OrderDate|clustered located on PS_Orders|OrderDate PK_Orders|nonclustered,unique,primary key located on PS_Orders|OrderID, CustomerID, OrderDate ************************************************************************/ EXEC sp_helpindex 'dbo.Orders' /********************************************************************** 6. 從SQL Server 2000 NorthWind 導入測試數據 ***********************************************************************/ INSERT INTO dbo.Orders SELECT OrderID, CustomerID, EmployeeID, OrderDate FROM Northwind.dbo.Orders /************************************************************************ 7. 查看分區表各分區數據情況(數據行數,最大最小OrderDate 值) *************************************************************************/ SELECT PARTITION = $PARTITION.PF_Orders_OrderDateRange(OrderDate), ROWS = COUNT(*), MinVal = MIN(OrderDate), MaxVal = MAX(OrderDate) FROM dbo.Orders GROUP BY $PARTITION.PF_Orders_OrderDateRange(OrderDate) ORDER BY PARTITION GO /************************************************************************ 在目前的測試數據中,並沒有大於1999年的數據,所以在上面的查詢結果中並沒有 看到第個分區的信息: PARTITION,ROWS,MinVal,MaxVal 1 152 1996-07-04 00:00:00.000 1996-12-31 00:00:00.000 2 408 1997-01-01 00:00:00.000 1997-12-31 00:00:00.000 3 270 1998-01-01 00:00:00.000 1998-05-06 00:00:00.000 *************************************************************************/ -- 插入一條測試數據 INSERT INTO dbo.Orders VALUES(11111,'TEST',1,'2000-10-10 10:10:10:100') -- 再次查詢 SELECT PARTITION = $PARTITION.PF_Orders_OrderDateRange(OrderDate), ROWS = COUNT(*), MinVal = MIN(OrderDate), MaxVal = MAX(OrderDate) FROM dbo.Orders GROUP BY $PARTITION.PF_Orders_OrderDateRange(OrderDate) ORDER BY PARTITION /************************************************************************ 查詢結果顯示了個分區的信息 PARTITION,ROWS,MinVal,MaxVal 1 152 1996-07-04 00:00:00.000 1996-12-31 00:00:00.000 2 408 1997-01-01 00:00:00.000 1997-12-31 00:00:00.000 3 270 1998-01-01 00:00:00.000 1998-05-06 00:00:00.000 4 1 2000-10-10 10:10:10.100 2000-10-10 10:10:10.100 *************************************************************************/ GO /************************************************************************* ************* 切換分區表的一個分區到普通數據表*************************** ************* Partition to Table ****************************************/ /************************************************************************* 1. 首先建立普通數據表Orders_1998,該表用來存放訂單日期為1998 年的所有數據 2. 分區到普通表的切換,最好滿足以下的前提條件: a. 普通表必須建立在分區表切換分區所在的文件組上ON [PRIMARY] b. 普通表的表結構跟分區表的一致 c. 普通表上的索引要跟分區表一致(聚集索引,非聚集索引) d. 普通表必須是空表,不能有任何數據 *************************************************************************/ IF OBJECT_ID('Orders_1998') IS NOT NULL DROP TABLE Orders_1998 GO CREATE TABLE dbo.Orders_1998 ( OrderID INT NOT NULL, CustomerID VARCHAR(10) NOT NULL, EmployeeID INT NOT NULL, OrderDate DATETIME NOT NULL )ON [PRIMARY] GO -- 添加聚集索引,和分區表一致 CREATE CLUSTERED INDEX IXC_Orders1998_OrderDate ON dbo.Orders_1998(OrderDate) GO -- 添加主鍵,和分區表一致 ALTER TABLE dbo.Orders_1998 ADD CONSTRAINT PK_Orders_1998 PRIMARY KEY(OrderID,CustomerID,OrderDate) GO /*************************************************************************** ** 開始切換分區表Orders 第三個分區的數據(1998年的數據)到普通表Orders_1998 ** 關鍵字- SWITCH PARTITION [NUMBER] TO [History Table] ***************************************************************************/ ALTER TABLE dbo.Orders SWITCH PARTITION 3 TO dbo.Orders_1998 /*************************************************************************** 查詢源分區表結果 分區號為的數據已經沒有了 1 152 1996-07-04 00:00:00.000 1996-12-31 00:00:00.000 2 408 1997-01-01 00:00:00.000 1997-12-31 00:00:00.000 4 1 2000-10-10 10:10:10.100 2000-10-10 10:10:10.100 ***************************************************************************/ SELECT PARTITION = $PARTITION.PF_Orders_OrderDateRange(OrderDate), ROWS = COUNT(*), MinVal = MIN(OrderDate), MaxVal = MAX(OrderDate) FROM dbo.Orders GROUP BY $PARTITION.PF_Orders_OrderDateRange(OrderDate) ORDER BY PARTITION /*************************************************************************** 查詢存檔表結果 3 270 1998-01-01 00:00:00.000 1998-05-06 00:00:00.000 ***************************************************************************/ SELECT PARTITION = $PARTITION.PF_Orders_OrderDateRange(OrderDate), ROWS = COUNT(*), MinVal = MIN(OrderDate), MaxVal = MAX(OrderDate) FROM dbo.Orders_1998 GROUP BY $PARTITION.PF_Orders_OrderDateRange(OrderDate) ORDER BY PARTITION /************************************************************************ ************* 切換普通表數據到分區表的一個分區中 ********************* ************* Table to Partition ************************/ /************************************************************************* 上面我們已經把分區表Orders 第三個分區的數據切換到普通表Orders_1998 中了, 現在我們再切換回來: **************************************************************************/ ALTER TABLE dbo.Orders_1998 SWITCH PARTITION 3 TO dbo.Orders /************************************************************************* 錯誤信息: Msg 4911, Level 16, State 2, Line 1 Cannot specify a partitioned table without partition number in ALTER TABLE SWITCH statement. The table 'SSISDemoDB.dbo.Orders' is partitioned. 原因: 實際上應該是將dbo.Orders_1998 表中的數據SWITCH 到dbo.Orders 表的 Partition 分區中. 而不能說是將dbo.Orders_1998 的分區的數據SWITCH 到dbo.Orders 全表中 **************************************************************************/ ALTER TABLE dbo.Orders_1998 SWITCH TO dbo.Orders PARTITION 3 /************************************************************************* 錯誤信息: Msg 4982, Level 16, State 1, Line 1 ALTER TABLE SWITCH statement failed. Check constraints of source table 'dbo.Orders_1998' allow values that are not allowed by range defined by partition 3 on target table 'dbo.Orders'. 原因: 表dbo.Orders 的數據經過分區函數的分區列定義, 各個分區的數據實際上已經經過 了數據約束檢查,符合分區邊界范圍(Range)的數據才會錄入到各個分區中. 但是在歷史表/存檔表dbo.Orders_1998中的數據實際上是沒有邊界約束的,比如完全 可以手動的插入一條年的數據,這樣一來在進行SWITCH時肯定是不會成功的. 所以在SWITCH時,先進行了約束性檢查,盡管沒有不符合規范的數據,但是有潛在的威脅. 所以在SWITCH之前,先為dbo.Orders_1998添加一個檢查約束,並再次SWITCH,成功! **************************************************************************/ ALTER TABLE dbo.Orders_1998 ADD CONSTRAINT CK_Orders1998_OrderDate CHECK(OrderDate>='1998-01-01' AND OrderDate<'1999-01-01') ALTER TABLE dbo.Orders_1998 SWITCH TO dbo.Orders PARTITION 3 /*************************************************************************** 查詢源分區表結果,分區的數據已經從dbo.Orders_1998 回來了 1 152 1996-07-04 00:00:00.000 1996-12-31 00:00:00.000 2 408 1997-01-01 00:00:00.000 1997-12-31 00:00:00.000 3 270 1998-01-01 00:00:00.000 1998-05-06 00:00:00.000 4 1 2000-10-10 10:10:10.100 2000-10-10 10:10:10.100 ***************************************************************************/ SELECT PARTITION = $PARTITION.PF_Orders_OrderDateRange(OrderDate), ROWS = COUNT(*), MinVal = MIN(OrderDate), MaxVal = MAX(OrderDate) FROM dbo.Orders GROUP BY $PARTITION.PF_Orders_OrderDateRange(OrderDate) ORDER BY PARTITION /*************************************************************************** 查詢存檔表結果,沒有任何數據,已經成功SWITCH to Orders 表的PARTITION 3 ***************************************************************************/ SELECT PARTITION = $PARTITION.PF_Orders_OrderDateRange(OrderDate), ROWS = COUNT(*), MinVal = MIN(OrderDate), MaxVal = MAX(OrderDate) FROM dbo.Orders_1998 GROUP BY $PARTITION.PF_Orders_OrderDateRange(OrderDate) ORDER BY PARTITION /**************************************************************************** 所以在進行存檔表的數據向分區表遷移過程中(TABLE TO PARTITION), 相比(PARTITION TO TABLE)多一個條件: 普通表必須加上和分區數據范圍一致的約束條件. *****************************************************************************/ /************************************************************************ ************* 切換分區表數據到分區表 ******************************** ************* PARTITION TO PARTITION **********************************/ /************************************************************************* -- 新的存檔分區表在結構上和源分區表是一致的,包括分區函數和分區方案, 但是需要重新創建,不能簡單地直接使用dbo.Orders 表上的分區函數和分區方案, 因為他們之間有綁定關系. **************************************************************************/ IF OBJECT_ID('OrdersArchive') IS NOT NULL DROP TABLE OrdersArchive GO IF EXISTS (SELECT * FROM sys.partition_schemes WHERE name = 'PS_OrdersArchive') DROP PARTITION SCHEME PS_OrdersArchive GO IF EXISTS (SELECT * FROM sys.partition_functions WHERE name = 'PF_OrdersArchive_OrderDateRange') DROP PARTITION FUNCTION PF_OrdersArchive_OrderDateRange GO CREATE PARTITION FUNCTION PF_OrdersArchive_OrderDateRange(DATETIME) AS RANGE RIGHT FOR VALUES ( '1997-01-01', '1998-01-01', '1999-01-01' ) GO CREATE PARTITION SCHEME PS_OrdersArchive AS -- 分區Scheme和分區函數綁定了 PARTITION PF_OrdersArchive_OrderDateRange TO ([primary],[primary],[primary],[primary]) GO CREATE TABLE dbo.OrdersArchive ( OrderID INT NOT NULL, CustomerID VARCHAR(10) NOT NULL, EmployeeID INT NOT NULL, OrderDate DATETIME NOT NULL ) -- 表和分區Scheme綁定了 ON PS_OrdersArchive(OrderDate) GO CREATE CLUSTERED INDEX IXC_OrdersArchive_OrderDate ON dbo.OrdersArchive(OrderDate) ALTER TABLE dbo.OrdersArchive ADD CONSTRAINT PK_OrdersArchive PRIMARY KEY(OrderID, CustomerID,OrderDate) GO /********************************************************************************* 開始切換分區 **********************************************************************************/ ALTER TABLE dbo.Orders SWITCH PARTITION 1 TO dbo.OrdersArchive PARTITION 1 ALTER TABLE dbo.Orders SWITCH PARTITION 2 TO dbo.OrdersArchive PARTITION 2 ALTER TABLE dbo.Orders SWITCH PARTITION 3 TO dbo.OrdersArchive PARTITION 3 /*************************************************************************** 查詢源分區表結果,只會有分區的數據 4 1 2000-10-10 10:10:10.100 2000-10-10 10:10:10.100 ***************************************************************************/ SELECT PARTITION = $PARTITION.PF_Orders_OrderDateRange(OrderDate), ROWS = COUNT(*), MinVal = MIN(OrderDate), MaxVal = MAX(OrderDate) FROM dbo.Orders GROUP BY $PARTITION.PF_Orders_OrderDateRange(OrderDate) ORDER BY PARTITION /*************************************************************************** 查詢存檔表結果,已經成功轉移 1 152 1996-07-04 00:00:00.000 1996-12-31 00:00:00.000 2 408 1997-01-01 00:00:00.000 1997-12-31 00:00:00.000 3 270 1998-01-01 00:00:00.000 1998-05-06 00:00:00.000 ***************************************************************************/ SELECT PARTITION = $PARTITION.PF_OrdersArchive_OrderDateRange(OrderDate), ROWS = COUNT(*), MinVal = MIN(OrderDate), MaxVal = MAX(OrderDate) FROM dbo.OrdersArchive GROUP BY $PARTITION.PF_OrdersArchive_OrderDateRange(OrderDate) ORDER BY PARTITION /*************************************************************************** 總結: 分區表分區切換並沒有真正去移動數據,而是SQL Server 在系統底層改變了表 的元數據。因此分區表分區切換是高效,快速,靈活的.利用分區表的分區切換功能, 我們可以快速加載數據到分區表.卸載分區數據到普通表,然後TRUNCATE 普通表, 以實現快速刪除分區表數據,快速歸檔不活躍數據到歷史表。 ****************************************************************************/
注 : 已經不記得原博客地址了, 這篇日志是基於別人的分析成果之上加上自己親自實踐, 思考, 重 新添加了一些代碼和注釋. 在注解和結論驗證方面按照自己的理解做出了還算比較細致的說明,對剛接觸 表分區概念的朋友們相信會有很大的幫助. 我也是通過這種方式學習和掌握了表分區的一些基礎操作步 驟和處理方式.