插入,更新,刪除操作在具有大量數據的表中會變的很慢。通過分區表的分區交換可以快速實現這個過程。
分區交換的條件
分區交換總是涉及兩個表。數據從源表交換到目標表。所以目標表必須總是空的。
分區交換有很多要求的條件,下面是一些比較重要的:
- 源表和目標表(或者分區)必須有一樣的列,索引,並且使用同樣的分區列。
- 源表和目標表(或者分區)必須在同一個文件組中
- 目標表(或者分區)必須是空的
如果這些條件不滿足,會報錯。
分區交換示例
分區交換要使用 ALTER TABLE SWITCH 語法。下面是使用這個語法的4中方式:
- 從一個無分區的表交換到另一個無分區的表
- 從一個無分區的表交換到另一個分區表的一個分區
- 從一個分區表的一個分區交換到另一個無分區的表
- 從一個分區表的一個分區交換到另一個分區表的一個分區
下面的例子中,不會創建任何的索引,並且它們所有的分區都在PRIMARY文件組中。
這些示例並不意味着在實際使用時的例子。
1.無分區表到無分區表的交換
第一種方式,交換一個無分區表的所有數據到另一個空的無分區表
ALTER TABLE Source SWITCH TO Target
交換前:
交換后:
這種方式不是很常用,但是它確實是學習 ALTER TABLE SWITCH語法的比較好的方式,
因為它不要求必須要創建 分區函數(partition functions) 和 分區架構(partition schemes):
-- Drop objects if they already exist IF EXISTS (SELECT * FROM sys.tables WHERE name = N'SalesSource') DROP TABLE SalesSource; IF EXISTS (SELECT * FROM sys.tables WHERE name = N'SalesTarget') DROP TABLE SalesTarget; -- Create the Non-Partitioned Source Table (Heap) on the [PRIMARY] filegroup CREATE TABLE SalesSource ( SalesDate DATE, Quantity INT ) ON [PRIMARY]; -- Insert test data INSERT INTO SalesSource(SalesDate, Quantity) SELECT DATEADD(DAY,dates.n-1,'2012-01-01') AS SalesDate, qty.n AS Quantity FROM GetNums(DATEDIFF(DD,'2012-01-01','2016-01-01')) dates CROSS JOIN GetNums(1000) AS qty; -- Create the Non-Partitioned Target Table (Heap) on the [PRIMARY] filegroup CREATE TABLE SalesTarget ( SalesDate DATE, Quantity INT ) ON [PRIMARY]; -- Verify row count before switch SELECT COUNT(*) FROM SalesSource; -- 1461000 rows SELECT COUNT(*) FROM SalesTarget; -- 0 rows -- Turn on statistics SET STATISTICS TIME ON; -- Is it really that fast...? ALTER TABLE SalesSource SWITCH TO SalesTarget; -- YEP! SUPER FAST! -- Turn off statistics SET STATISTICS TIME OFF; -- Verify row count after switch SELECT COUNT(*) FROM SalesSource; -- 0 rows SELECT COUNT(*) FROM SalesTarget; -- 1461000 rows -- If we try to switch again we will get an error: ALTER TABLE SalesSource SWITCH TO SalesTarget; -- Msg 4905, ALTER TABLE SWITCH statement failed. The target table 'SalesTarget' must be empty. -- But if we try to switch back to the now empty Source table, it works: ALTER TABLE SalesTarget SWITCH TO SalesSource; -- (...STILL SUPER FAST!)
2.無分區表到有分區表的交換
第二種方式,使用 ALTER TABLE SWITCH 語法交換無分區表的所有數據到一個分區表指定的空的分區。
ALTER TABLE Source SWITCH TO Target PARTITION 1
交換前:
交換后:
如下sql
-- Drop objects if they already exist IF EXISTS (SELECT * FROM sys.tables WHERE name = N'SalesSource') DROP TABLE SalesSource; IF EXISTS (SELECT * FROM sys.tables WHERE name = N'SalesTarget') DROP TABLE SalesTarget; IF EXISTS (SELECT * FROM sys.partition_schemes WHERE name = N'psSales') DROP PARTITION SCHEME psSales; IF EXISTS (SELECT * FROM sys.partition_functions WHERE name = N'pfSales') DROP PARTITION FUNCTION pfSales; -- Create the Partition Function CREATE PARTITION FUNCTION pfSales (DATE) AS RANGE RIGHT FOR VALUES ('2013-01-01', '2014-01-01', '2015-01-01'); -- Create the Partition Scheme CREATE PARTITION SCHEME psSales AS PARTITION pfSales ALL TO ([Primary]); -- Create the Non-Partitioned Source Table (Heap) on the [PRIMARY] filegroup CREATE TABLE SalesSource ( SalesDate DATE, Quantity INT ) ON [PRIMARY]; -- Insert test data INSERT INTO SalesSource(SalesDate, Quantity) SELECT DATEADD(DAY,dates.n-1,'2012-01-01') AS SalesDate, qty.n AS Quantity FROM GetNums(DATEDIFF(DD,'2012-01-01','2013-01-01')) dates CROSS JOIN GetNums(1000) AS qty; -- Create the Partitioned Target Table (Heap) on the Partition Scheme CREATE TABLE SalesTarget ( SalesDate DATE, Quantity INT ) ON psSales(SalesDate); -- Insert test data INSERT INTO SalesTarget(SalesDate, Quantity) SELECT DATEADD(DAY,dates.n-1,'2013-01-01') AS SalesDate, qty.n AS Quantity FROM GetNums(DATEDIFF(DD,'2013-01-01','2016-01-01')) dates CROSS JOIN GetNums(1000) AS qty; -- Verify row count before switch SELECT COUNT(*) FROM SalesSource; -- 366000 rows SELECT pstats.partition_number AS PartitionNumber ,pstats.row_count AS PartitionRowCount FROM sys.dm_db_partition_stats AS pstats WHERE pstats.object_id = OBJECT_ID('SalesTarget') ORDER BY PartitionNumber; -- 0 rows in Partition 1, 365000 rows in Partitions 2-4 -- Turn on statistics SET STATISTICS TIME ON; -- Is it really that fast...? ALTER TABLE SalesSource SWITCH TO SalesTarget PARTITION 1; -- NOPE! We get an error: -- Msg 4982, ALTER TABLE SWITCH statement failed. Check constraints of source table 'SalesSource' -- allow values that are not allowed by range defined by partition 1 on target table 'Sales'. -- Add constraints to the source table to ensure it only contains data with values -- that are allowed in partition 1 on the target table ALTER TABLE SalesSource WITH CHECK ADD CONSTRAINT ckMinSalesDate CHECK (SalesDate IS NOT NULL AND SalesDate >= '2012-01-01'); ALTER TABLE SalesSource WITH CHECK ADD CONSTRAINT ckMaxSalesDate CHECK (SalesDate IS NOT NULL AND SalesDate < '2013-01-01'); -- Try again. Is it really that fast...? ALTER TABLE SalesSource SWITCH TO SalesTarget PARTITION 1; -- YEP! SUPER FAST! -- Turn off statistics SET STATISTICS TIME OFF; -- Verify row count after switch SELECT COUNT(*) FROM SalesSource; -- 0 rows SELECT pstats.partition_number AS PartitionNumber ,pstats.row_count AS PartitionRowCount FROM sys.dm_db_partition_stats AS pstats WHERE pstats.object_id = OBJECT_ID('SalesTarget') ORDER BY PartitionNumber; -- 366000 rows in Partition 1, 365000 rows in Partitions 2-4
3.分區表交換到一個無分區表
第三種方式,使用ALTER TABLE SWITCH語法,把一個分區表的指定分區的數據交換到一個空的無分區表。
ALTER TABLE Source SWITCH PARTITION 1 TO Target
交換前:
交換后:
如下sql:
-- Drop objects if they already exist IF EXISTS (SELECT * FROM sys.tables WHERE name = N'SalesSource') DROP TABLE SalesSource; IF EXISTS (SELECT * FROM sys.tables WHERE name = N'SalesTarget') DROP TABLE SalesTarget; IF EXISTS (SELECT * FROM sys.partition_schemes WHERE name = N'psSales') DROP PARTITION SCHEME psSales; IF EXISTS (SELECT * FROM sys.partition_functions WHERE name = N'pfSales') DROP PARTITION FUNCTION pfSales; -- Create the Partition Function CREATE PARTITION FUNCTION pfSales (DATE) AS RANGE RIGHT FOR VALUES ('2013-01-01', '2014-01-01', '2015-01-01'); -- Create the Partition Scheme CREATE PARTITION SCHEME psSales AS PARTITION pfSales ALL TO ([Primary]); -- Create the Partitioned Source Table (Heap) on the Partition Scheme CREATE TABLE SalesSource ( SalesDate DATE, Quantity INT ) ON psSales(SalesDate); -- Insert test data INSERT INTO SalesSource(SalesDate, Quantity) SELECT DATEADD(DAY,dates.n-1,'2012-01-01') AS SalesDate, qty.n AS Quantity FROM GetNums(DATEDIFF(DD,'2012-01-01','2016-01-01')) dates CROSS JOIN GetNums(1000) AS qty; -- Create the Non-Partitioned Target Table (Heap) on the [PRIMARY] filegroup CREATE TABLE SalesTarget ( SalesDate DATE, Quantity INT ) ON [PRIMARY]; -- Verify row count before switch SELECT pstats.partition_number AS PartitionNumber ,pstats.row_count AS PartitionRowCount FROM sys.dm_db_partition_stats AS pstats WHERE pstats.object_id = OBJECT_ID('Sales') ORDER BY PartitionNumber; -- 366000 rows in Partition 1, 365000 rows in Partitions 2-4 SELECT COUNT(*) FROM SalesTarget; -- 0 rows -- Turn on statistics SET STATISTICS TIME ON; -- Is it really that fast...? ALTER TABLE SalesSource SWITCH PARTITION 1 TO SalesTarget; -- YEP! SUPER FAST! -- Turn off statistics SET STATISTICS TIME OFF; -- Verify row count after switch SELECT pstats.partition_number AS PartitionNumber ,pstats.row_count AS PartitionRowCount FROM sys.dm_db_partition_stats AS pstats WHERE pstats.object_id = OBJECT_ID('SalesSource') ORDER BY PartitionNumber; -- 0 rows in Partition 1, 365000 rows in Partitions 2-4 SELECT COUNT(*) FROM SalesTarget; -- 366000 rows
4.分區表交換到分區表
第四種方式,使用 ALTER TABLE SWITCH 語法,把一個分區表指定分區的數據交換到另一個分區表的空的指定分區中。
ALTER TABLE Source SWITCH PARTITION 1 TO Target PARTITION 1
交換前:
交換后:
如下sql:
-- Drop objects if they already exist IF EXISTS (SELECT * FROM sys.tables WHERE name = N'SalesSource') DROP TABLE SalesSource; IF EXISTS (SELECT * FROM sys.tables WHERE name = N'SalesTarget') DROP TABLE SalesTarget; IF EXISTS (SELECT * FROM sys.partition_schemes WHERE name = N'psSales') DROP PARTITION SCHEME psSales; IF EXISTS (SELECT * FROM sys.partition_functions WHERE name = N'pfSales') DROP PARTITION FUNCTION pfSales; -- Create the Partition Function CREATE PARTITION FUNCTION pfSales (DATE) AS RANGE RIGHT FOR VALUES ('2013-01-01', '2014-01-01', '2015-01-01'); -- Create the Partition Scheme CREATE PARTITION SCHEME psSales AS PARTITION pfSales ALL TO ([Primary]); -- Create the Partitioned Source Table (Heap) on the Partition Scheme CREATE TABLE SalesSource ( SalesDate DATE, Quantity INT ) ON psSales(SalesDate); -- Insert test data INSERT INTO SalesSource(SalesDate, Quantity) SELECT DATEADD(DAY,dates.n-1,'2012-01-01') AS SalesDate, qty.n AS Quantity FROM GetNums(DATEDIFF(DD,'2012-01-01','2013-01-01')) dates CROSS JOIN GetNums(1000) AS qty; -- Create the Partitioned Target Table (Heap) on the Partition Scheme CREATE TABLE SalesTarget ( SalesDate DATE, Quantity INT ) ON psSales(SalesDate); -- Insert test data INSERT INTO SalesTarget(SalesDate, Quantity) SELECT DATEADD(DAY,dates.n-1,'2013-01-01') AS SalesDate, qty.n AS Quantity FROM GetNums(DATEDIFF(DD,'2013-01-01','2016-01-01')) dates CROSS JOIN GetNums(1000) AS qty; -- Verify row count before switch SELECT pstats.partition_number AS PartitionNumber ,pstats.row_count AS PartitionRowCount FROM sys.dm_db_partition_stats AS pstats WHERE pstats.object_id = OBJECT_ID('SalesSource') ORDER BY PartitionNumber; -- 366000 rows in Partition 1, 0 rows in Partitions 2-4 SELECT pstats.partition_number AS PartitionNumber ,pstats.row_count AS PartitionRowCount FROM sys.dm_db_partition_stats AS pstats WHERE pstats.object_id = OBJECT_ID('SalesTarget') ORDER BY PartitionNumber; -- 0 rows in Partition 1, 365000 rows in Partitions 2-4 -- Turn on statistics SET STATISTICS TIME ON; -- Is it really that fast...? ALTER TABLE SalesSource SWITCH PARTITION 1 TO SalesTarget PARTITION 1; -- YEP! SUPER FAST! -- Turn off statistics SET STATISTICS TIME OFF; -- Verify row count after switch SELECT pstats.partition_number AS PartitionNumber ,pstats.row_count AS PartitionRowCount FROM sys.dm_db_partition_stats AS pstats WHERE pstats.object_id = OBJECT_ID('SalesSource') ORDER BY PartitionNumber; -- 0 rows in Partition 1-4 SELECT pstats.partition_number AS PartitionNumber ,pstats.row_count AS PartitionRowCount FROM sys.dm_db_partition_stats AS pstats WHERE pstats.object_id = OBJECT_ID('SalesTarget') ORDER BY PartitionNumber; -- 366000 rows in Partition 1, 365000 rows in Partitions 2-4
錯誤信息(Error messages)
sql server 會提供詳細的信息,當條件不滿足時。你可以通過運行下面的查詢,查看與 ALTER TABLE SWITCH有關的信息。
SELECT message_id, text FROM sys.messages WHERE language_id = 1033 AND text LIKE '%ALTER TABLE SWITCH%';