一、前言
在MSDN上看到一篇關於SQL Server 表分區的文檔:已分區索引的特殊指導原則,如果你對表分區沒有實戰經驗的話是比較難理解文檔里面描述的意思。這里我就里面的一些概念進行講解,方便大家的交流。
(Figure0:索引與基表對齊)
二、解讀
“索引要與其基表對齊,並不需要與基表參與相同的命名分區函數。但是,索引和基表的分區函數在實質上必須相同,即:
1) 分區函數的參數具有相同的數據類型;
2) 分區函數定義了相同數目的分區;
3) 分區函數為分區定義了相同的邊界值。”
下面我們進行測試:
--1.創建文件組 ALTER DATABASE [Test] ADD FILEGROUP [FG_TestUnique_Id_01] ALTER DATABASE [Test] ADD FILEGROUP [FG_TestUnique_Id_02] ALTER DATABASE [Test] ADD FILEGROUP [FG_TestUnique_Id_03] --2.創建文件 ALTER DATABASE [Test] ADD FILE (NAME = N'FG_TestUnique_Id_01_data',FILENAME = N'E:\DataBase\FG_TestUnique_Id_01_data.ndf',SIZE = 1MB, FILEGROWTH = 1MB ) TO FILEGROUP [FG_TestUnique_Id_01]; ALTER DATABASE [Test] ADD FILE (NAME = N'FG_TestUnique_Id_02_data',FILENAME = N'E:\DataBase\FG_TestUnique_Id_02_data.ndf',SIZE = 1MB, FILEGROWTH = 1MB ) TO FILEGROUP [FG_TestUnique_Id_02]; ALTER DATABASE [Test] ADD FILE (NAME = N'FG_TestUnique_Id_03_data',FILENAME = N'E:\DataBase\FG_TestUnique_Id_03_data.ndf',SIZE = 1MB, FILEGROWTH = 1MB ) TO FILEGROUP [FG_TestUnique_Id_03]; --3.創建分區函數 CREATE PARTITION FUNCTION Fun_TestUnique_Id(INT) AS RANGE RIGHT FOR VALUES(10000000,20000000) --4.創建分區方案 CREATE PARTITION SCHEME Sch_TestUnique_Id AS PARTITION Fun_TestUnique_Id TO([FG_TestUnique_Id_01],[FG_TestUnique_Id_02],[FG_TestUnique_Id_03])
上面的SQL腳本創建了分區函數:Fun_TestUnique_Id(INT)和分區方案:[Sch_TestUnique_Id]。下面我們創建類似的分區函數:Fun_TestUnique_SiteId(INT)和分區方案:[Sch_TestUnique_SiteId]。這兩個函數完全符合上面提到的3個條件:
1) 分區函數的參數具有相同的數據類型;(都是Int類型)
2) 分區函數定義了相同數目的分區;(都是3個分區)
3) 分區函數為分區定義了相同的邊界值。”(邊界值都是10000000,20000000)
--1.創建文件組 ALTER DATABASE [Test] ADD FILEGROUP [FG_TestUnique_SiteId_01] ALTER DATABASE [Test] ADD FILEGROUP [FG_TestUnique_SiteId_02] ALTER DATABASE [Test] ADD FILEGROUP [FG_TestUnique_SiteId_03] --2.創建文件 ALTER DATABASE [Test] ADD FILE (NAME = N'FG_TestUnique_SiteId_01_data',FILENAME = N'E:\DataBase\FG_TestUnique_SiteId_01_data.ndf',SIZE = 1MB, FILEGROWTH = 1MB ) TO FILEGROUP [FG_TestUnique_SiteId_01]; ALTER DATABASE [Test] ADD FILE (NAME = N'FG_TestUnique_SiteId_02_data',FILENAME = N'E:\DataBase\FG_TestUnique_SiteId_02_data.ndf',SIZE = 1MB, FILEGROWTH = 1MB ) TO FILEGROUP [FG_TestUnique_SiteId_02]; ALTER DATABASE [Test] ADD FILE (NAME = N'FG_TestUnique_SiteId_03_data',FILENAME = N'E:\DataBase\FG_TestUnique_SiteId_03_data.ndf',SIZE = 1MB, FILEGROWTH = 1MB ) TO FILEGROUP [FG_TestUnique_SiteId_03]; --3.創建分區函數 CREATE PARTITION FUNCTION Fun_TestUnique_SiteId(INT) AS RANGE RIGHT FOR VALUES(10000000,20000000) --4.創建分區方案 CREATE PARTITION SCHEME Sch_TestUnique_SiteId AS PARTITION Fun_TestUnique_SiteId TO([FG_TestUnique_SiteId_01],[FG_TestUnique_SiteId_02],[FG_TestUnique_SiteId_03])
接下來創建一個以這個分區方案進行分區的表[TestUnique];這個表的聚集索引是創建在分區方案:[Sch_TestUnique_Id]上的。接着創建一個唯一索引:[IX_TestUnique_SiteIdUrl]是創建在分區方案[Sch_TestUnique_SiteId]上的。那么這個唯一索引跟基表是對齊的嘛?
--5.創建分區表 CREATE TABLE [dbo].[TestUnique]( [Id] [int] IDENTITY(600000000,1) NOT FOR REPLICATION NOT NULL, [SiteId] [int] NULL, [Url] [nvarchar](420) NULL, [PublishOn] [datetime] NULL, [AddOn] [datetime] NULL, CONSTRAINT [PK_Archive] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = ON, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [Sch_TestUnique_Id]([Id]) ) ON [Sch_TestUnique_Id]([Id]) GO --6.創建唯一索引 CREATE NONCLUSTERED INDEX [IX_TestUnique_SiteIdUrl] ON [dbo].[TestUnique] ( [SiteId] ASC, [Url] ASC )WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [Sch_TestUnique_SiteId]([SiteId]) GO
其實很明細,這個唯一索引[IX_TestUnique_SiteIdUrl]與基表是不對齊的,因為他們使用了不同的字段,一個是Id值,一個是SiteId值,很簡單,因為Id為10000000的時候SiteId不一定也是10000000,所以他們沒有辦法對齊的;只要你進行一些切換分區就知道:
--插入測試數據 SET IDENTITY_INSERT [TestUnique] ON INSERT INTO [TestDB].[dbo].[TestUnique] ([Id],[SiteId],[Url] ,[PublishOn] ,[AddOn]) VALUES (10000010,10000009,'http://baidu.com',getdate(),getdate()) INSERT INTO [TestDB].[dbo].[TestUnique] ([Id],[SiteId],[Url] ,[PublishOn] ,[AddOn]) VALUES (20000010,20000008,'http://baidu.com',getdate(),getdate()) SET IDENTITY_INSERT [TestUnique] OFF --創建切換分區臨時表 CREATE TABLE [dbo].[Temp_TestUnique]( [Id] [int] IDENTITY(600000000,1) NOT FOR REPLICATION NOT NULL, [SiteId] [int] NULL, [Url] [nvarchar](420) NULL, [PublishOn] [datetime] NULL, [AddOn] [datetime] NULL, CONSTRAINT [PK_TempArchive] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = ON, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [Sch_TestUnique_Id]([Id]) ) ON [Sch_TestUnique_Id]([Id]) GO CREATE NONCLUSTERED INDEX [IX_TestUnique_SiteIdUrl] ON [dbo].[Temp_TestUnique] ( [SiteId] ASC, [Url] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Sch_TestUnique_SiteId]([SiteId]) GO --切換分區 ALTER TABLE [dbo].[TestUnique] SWITCH PARTITION 2 TO [dbo].[Temp_TestUnique] PARTITION 2
執行上面的切換分區SQL會報下面的錯誤:
消息4912,級別16,狀態1,第2 行
'ALTER TABLE SWITCH' 語句失敗。用於對表'Test.dbo.TestUnique' 進行分區的列集與用於對索引'IX_TestUnique_SiteIdUrl' 進行分區的列集不同。
[Sch_TestUnique_Id]([Id])與[Sch_TestUnique_SiteId]([SiteId])是屬於不同的字段分區,如果換成[Sch_TestUnique_Id]([Id])與[Sch_TestUnique_SiteId]([Id]),雖然分區方案的名稱不同,但是實質是一樣的(參考上面3個條件的描述),這種情況我們也說索引與基表對齊了,可以進行切換分區了。下面是執行切換分區的效果圖:
(Figure1:交換分區前)
(Figure2:交換分區后)
(Figure3:分區文件)
總結:使用不同的分區方案進行對齊的好處是讓數據與索引分開存儲,存儲到不同的文件,但是它又是符合基表與索引是對齊,同時方便使用切換分區進行歷史數據歸檔;
“先設計一個已分區表,然后為該表創建索引。執行此操作時,SQL Server 將使用與該表相同的分區方案和分區依據列自動對索引進行分區。因此,索引的分區方式實質上與表的分區方式相同。這將使索引與表“對齊”。
如果在創建時指定了不同的分區方案或單獨的文件組來存儲索引,則 SQL Server 不會將索引與表對齊。“
不同的分區方案並不是指不同的分區方案名,而是指不一樣的分區方案結構。
三、參考文獻
->已分區索引的特殊指導原則(唯一索引)



