1. 程式人生 > >SQL Server 解讀【已分割槽索引的特殊指導原則】(1)- 索引對齊(轉載)

SQL Server 解讀【已分割槽索引的特殊指導原則】(1)- 索引對齊(轉載)

一、前言


 

  在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 不會將索引與表對齊。“

不同的分割槽方案並不是指不同的分割槽方案名,而是指不一樣的分割槽方案結構。

 

 

三、參考文獻


 

定義了索引檢視時的分割槽切換

使用分割槽切換高效傳輸資料

已分割槽索引的特殊指導原則(唯一索引)

設計分割槽以管理資料子集

Special Guidelines for Partitioned Indexes

 

原文連結