【IT168 技術文檔】每個月都會有新數據添加到龐大的Orders數據表中,此時如果只對這一個表進行操作,則更新索引的過程將嚴重製約性能並產生大量碎片。為了進行優化,我們將通過獨立的兩個表進行配合,即當有新數據產生時,將舊數據從分區表中切換出來,然後將新數據添加到分區表中。
整個過程包含如下幾個步驟:
·準備好即將用於存放舊數據的表
·準備好存有新數據的表
·更改分區方案,以便使用新的文件組
·對分區函數進行更改,分裂出新的邊界點
注意:前4步均為影響到實際的分區表
·切換進來新數據
·將舊數據切換出去
注意:第5步和第6步的順序可以進行更改,且更改後執行速度更快
·合併邊界點
·備份/刪除舊數據
我們實驗所用到的分區數據表中包含的數據,因此我們將把數據作為一個分區直接切換進來。當進行分區切換的時候,只有元數據會發生更改,真正的數據並不會產生移動,因此速度非常快。
1.在不影響當前OrdersRange 分區表的前提下,為新數據做好準備
(1)在Solution Explorer 窗口,雙擊打開Script4 – RollingRangeScenario.sql.
(2)新建一個文件組,用於存放新的數據
ALTER DATABASE AdventureWorks2008Test
ADD FILEGROUP [2004Q3]
GO
(3)為文件組添加一個文件:
ALTER DATABASE AdventureWorks2008Test
ADD FILE
(NAME = N'2004Q3',
FILENAME = N'C:\AdventureWorks2008Test\2004Q3.ndf',
SIZE = 5MB,
MAXSIZE = 100MB,
FILEGROWTH = 5MB)
TO FILEGROUP [2004Q3]
GO
(4)接下來,我們要新建一個未分區的數據表,用於存放分區數據表中新建分區中的數據。該未分區數據表必須與分區數據表具有完全一致的結構和聚集索引。此外,為了能夠確保快速進行分區切換,還需要通過約束來確保此未分區數據表中的數據與分區數據表中新建分區的範圍相吻合。接下來我們將創建該數據表,插入數據,並創建聚集索引
CREATE TABLE AdventureWorks2008Test.[dbo].[Orders2004Q3]
(
[OrderID] [int] NOT NULL,
[EmployeeID] [int] NULL,
[VendorID] [int] NULL,
[TaxAmt] [money] NULL,
[Freight] [money] NULL,
[SubTotal] [money] NULL,
[Status] [tinyint] NOT NULL ,
[RevisionNumber] [tinyint] NULL,
[ModifiedDate] [datetime] NULL,
[ShipMethodID] tinyint NULL,
[ShipDate] [datetime] NOT NULL,
[OrderDate] [datetime] NOT NULL
CONSTRAINT Orders2004Q3MinDate
CHECK (OrderDate >= '20040701'),
[TotalDue] [money] NULL
) ON [2004Q3]
GO
ALTER TABLE AdventureWorks2008Test.[dbo].[Orders2004Q3]
ADD CONSTRAINT Orders2004Q3MaxDate
CHECK (OrderDate < '20041001')
go
---------------------------------------------
-- Populate new table with Q3 2004 data.
---------------------------------------------
INSERT INTO AdventureWorks2008Test.[dbo].Orders2004Q3
SELECT o.[PurchaseOrderID]
, o.[EmployeeID]
, o.[VendorID]
, o.[TaxAmt]
, o.[Freight]
, o.[SubTotal]
, o.[Status]
, o.[RevisionNumber]
, o.[ModifiedDate]
, o.[ShipMethodID]
, o.[ShipDate]
, o.[OrderDate]
, o.[TotalDue]
FROM AdventureWorks2008.Purchasing.PurchaseOrderHeader AS o
WHERE o.OrderDate >= '20040701'
AND o.OrderDate < '20041001'
GO
---------------------------------------------
-- The table *must* have the same clustered
-- index definition!
---------------------------------------------
CREATE CLUSTERED INDEX Orders2004Q3CLInd
ON Orders2004Q3(OrderDate, OrderID)
ON [2004Q3]
GO
2.為將要進行歸檔的數據做好準備
存放歸檔數據的數據表必須與分區數據表具有完全一致的結構和聚集索引。一會兒我們將把文件組2003Q3中的數據進行歸檔
(1)創建用於歸檔的數據表:
CREATE TABLE AdventureWorks2008Test.[dbo].[Orders2003Q3]
(
[OrderID] [int] NOT NULL,
[EmployeeID] [int] NULL,
[VendorID] [int] NULL,
[TaxAmt] [money] NULL,
[Freight] [money] NULL,
[SubTotal] [money] NULL,
[Status] [tinyint] NOT NULL ,
[RevisionNumber] [tinyint] NULL,
[ModifiedDate] [datetime] NULL,
[ShipMethodID] tinyint NULL,
[ShipDate] [datetime] NOT NULL,
[OrderDate] [datetime] NOT NULL,
[TotalDue] [money] NULL
) ON [2003Q3]
GO
---------------------------------------------
-- The table must have the same clustered
-- index definition!
---------------------------------------------
CREATE CLUSTERED INDEX Orders2003Q3CLInd
ON Orders2003Q3(OrderDate, OrderID)
ON [2003Q3]
GO
(2)執行如下代碼,進行分區切換。注意,此時只是將分區從分區表中移除,數據實際並沒有刪除,但在OrdersRange 數據表中將無法再看到這些數據,因為這些數據已經被「切換」到了Orders2003Q3 表中
ALTER TABLE OrdersRange
SWITCH PARTITION 2
TO Orders2003Q3
GO
3.驗證分區數據表中已經不再包含切換出去的數據
(1)為了確保分區 2中的數據已經被刪除,執行如下語句進行查看:
SELECT $partition.OrderDateRangePFN(OrderDate)
AS 'Parition Number'
, min(OrderDate) AS 'Min Order Date'
, max(OrderDate) AS 'Max Order Date'
, count(*) AS 'Rows In Partition'
FROM OrdersRange
GROUP BY $partition.OrderDateRangePFN(OrderDate)
ORDER BY 1
GO
(2)此時可以看到只有分區3,4,5中有數據
4.刪除已經廢棄的分區邊界
通過剛才所執行的查詢我們可以看到,只有分區3,4,5當中有數據,如何才能將所有分區向左移動一位?
此時我們只需要刪除最左側的分區邊界
(1)執行如下語句,從OrdersRange 分區表中刪除2003年第3季度的分區邊界:
ALTER PARTITION FUNCTION OrderDateRangePFN()
MERGE RANGE ('20030701')
GO
(2)此時我們的分區表中將只包含3個有數據的分區和1個空分區。執行如下語句進行核實,注意現在分區2,3,4當中有數據
SELECT $partition.OrderDateRangePFN(OrderDate)
AS 'Parition Number'
, min(OrderDate) AS 'Min Order Date'
, max(OrderDate) AS 'Max Order Date'
, count(*) AS 'Rows In Partition'
FROM OrdersRange
GROUP BY $partition.OrderDateRangePFN(OrderDate)
ORDER BY 1
GO
(3)Merge操作刪除了分區1,因此SQL Server對現有分區進行了重新編號,但並沒有移動任何數據,只是改變了分區號。正因如此,資料庫所使用的文件組並沒有發生改變。執行如下語句進行查詢:
SELECT * FROM sys.filegroups
(4)之前分區2存放在2003Q3 文件組,但現在該文件組已經不再與該分區表相關聯了。執行如下語句,可以查看各個分區及其相關聯的文件組:
SELECT ps.name AS PSName,
dds.destination_id AS PartitionNumber,
dds.data_space_id AS FileGroup,
fg.name AS FileGroupName
FROM (((sys.tables AS t
INNER JOIN sys.indexes AS i
ON (t.object_id = i.object_id))
INNER JOIN sys.partition_schemes AS ps
ON (i.data_space_id = ps.data_space_id))
INNER JOIN sys.destination_data_spaces AS dds
ON (ps.data_space_id =
dds.partition_scheme_id))
INNER JOIN sys.filegroups AS fg
ON dds.data_space_id = fg.data_space_id
WHERE (t.name = 'OrdersRange')
AND (i.index_id IN (0,1))
5.將新的文件組添加到分區方案中
前面我們查看了分區表當前的狀態,為了添加新的分區(從現有分區當中拆分出來),我們還要為新的分區準備一個存放位置。新的分區將存放在2004Q3 文件組中,該文件組我們前面已經創建。執行如下代碼將該文件組添加到分區方案中:
ALTER PARTITION SCHEME OrderDatePScheme
NEXT USED [2004Q3]
GO
6.更改數據表的約束
分區視圖非常依賴約束,而分區數據表對約束的依賴沒有這麼強。但出於數據完整性的考慮,此實驗中我們為數據表添加了約束。現有約束只允許添加2003Q3 到2004Q2之間的數據。為了能夠將新數據切換到分區表中,我們首先要更改此約束
(1)執行如下代碼,更改分區表的約束:
ALTER TABLE OrdersRange
ADD CONSTRAINT OrdersRangeMax
CHECK ([OrderDate] < '20041001')
go
ALTER TABLE OrdersRange
ADD CONSTRAINT OrdersRangeMin
CHECK ([OrderDate] >= '20031001')
go
ALTER TABLE OrdersRange
DROP CONSTRAINT OrdersRangeYear
go
(2)接下來執行下面的代碼,分裂出新的分區:
ALTER PARTITION FUNCTION OrderDateRangePFN()
SPLIT RANGE ('20040701')
GO
(3)將數據切換到新的分區中:
ALTER TABLE Orders2004Q3
SWITCH TO OrdersRange PARTITION 5
GO
(4)最後驗證數據:
SELECT $partition.OrderDateRangePFN(OrderDate)
AS 'Parition Number'
, min(OrderDate) AS 'Min Order Date'
, max(OrderDate) AS 'Max Order Date'
, count(*) AS 'Rows In Partition'
FROM OrdersRange
GROUP BY $partition.OrderDateRangePFN(OrderDate)
ORDER BY 1
GO
(5)關閉Script4 - RollingRangeScenario.sql.