1. 程式人生 > >Sql Server系列:分區表操作

Sql Server系列:分區表操作

red 可伸縮 ID 不同 一個 edate pan 添加分區 必須

1. 分區表簡介

  分區表在邏輯上是一個表,而物理上是多個表。從用戶角度來看,分區表和普通表是一樣的。使用分區表的主要目的是為改善大型表以及具有多個訪問模式的表的可伸縮性和可管理性。

  分區表是把數據按設定的標準劃分成區域存儲在不同的文件組中,使用分區可以快速而有效管理和訪問數據子集。

1.1> 適合做分區表的情況

  ? 數據庫中某個表的數據很多,在查詢數據時會明顯感覺到速度很慢,這個時候需要考慮分區表;

  ? 數據是分段的,如以年份為分隔的數據,對於當年的數據經常進行增刪改查操作,而對於往年的數據幾乎不做操作或只做查詢操作,這種情況可以使用分區表。對數據的操作如果只涉及一部分數據而不是全部數據的情況可以考慮分區表,如果一張表的數據經常使用且不管年份之類的因素經常對其增刪改查操作則最好不要分區。

1.2> 分區表的優點

  ? 分區表可以從物理上將一個大表分成幾個小表,但是從邏輯上來看還是一個大表。

  ? 對於具有多個CPU的系統,分區可以對表的操作通過並行的方式進行,可以提升訪問性能。

2. 創建分區表步驟

  創建分區表的步驟分為5步:

  (1)創建數據庫文件組

  (2)創建數據庫文件

  (3)創建分區函數

  (4)創建分區方案

  (5)創建分區表

2.1> 創建數據庫文件組

  新建示例數據庫Northwind,創建數據庫文件組和文件,添加文件組。

  技術分享圖片

2.2> 創建數據庫文件

  創建數據文件,並為數據文件分配文件組。

  技術分享圖片

  完成創建後的數據庫文件信息

  技術分享圖片

  通過SQL Server Profiler可以看到具體的創建數據庫的腳本如下:

技術分享圖片
CREATE DATABASE [Northwind]
 CONTAINMENT = NONE
 ON  PRIMARY 
( NAME = N‘Northwind‘, FILENAME = N‘F:\Database\Northwind\Northwind.mdf‘ , SIZE = 5120KB , FILEGROWTH = 1024KB ), 
 FILEGROUP [SECTION2010] 
( NAME = N‘Northwind_Data_2010‘, FILENAME = N‘F:\Database\Northwind\Northwind_Data_2010.ndf‘ , SIZE = 5120KB , FILEGROWTH = 1024KB ), 
 FILEGROUP [SECTION2011] 
( NAME = N‘Northwind_Data_2011‘, FILENAME = N‘F:\Database\Northwind\Northwind_Data_2011.ndf‘ , SIZE = 5120KB , FILEGROWTH = 1024KB ), 
 FILEGROUP [SECTION2012] 
( NAME = N‘Northwind_Data_2012‘, FILENAME = N‘F:\Database\Northwind\Northwind_Data_2012.ndf‘ , SIZE = 5120KB , FILEGROWTH = 1024KB ), 
 FILEGROUP [SECTION2013] 
( NAME = N‘Northwind_Data_2013‘, FILENAME = N‘F:\Database\Northwind\Northwind_Data_2013.ndf‘ , SIZE = 5120KB , FILEGROWTH = 1024KB ), 
 FILEGROUP [SECTION2014] 
( NAME = N‘Northwind_Data_2014‘, FILENAME = N‘F:\Database\Northwind\Northwind_Data_2014.ndf‘ , SIZE = 5120KB , FILEGROWTH = 1024KB )
 LOG ON 
( NAME = N‘Northwind_log‘, FILENAME = N‘F:\Database\Northwind\Northwind_log.ldf‘ , SIZE = 2048KB , FILEGROWTH = 10%)
技術分享圖片

  查看數據庫文件組SQL語句:

技術分享圖片

2.3> 創建分區函數

  創建分區函數Transact-SQL語法:

CREATE PARTITION FUNCTION partition_function_name ( input_parameter_type )
AS RANGE [ LEFT | RIGHT ] 
FOR VALUES ( [ boundary_value [ ,...n ] ] ) 
[ ; ]

  參數:  

  partition_function_name:分區函數的名稱。 分區函數名稱在數據庫內必須唯一,並且符合標識符的規則。

  input_parameter_type:用於分區的列的數據類型。 當用作分區列時,除 text、ntext、image、xml、timestamp、varchar(max)、nvarchar(max)、varbinary(max)、別名數據類型或 CLR 用戶定義數據類型外,所有數據類型均有效。

  boundary_value:為使用 partition_function_name 的已分區表或索引的每個分區指定邊界值。 如果 boundary_value 為空,則分區函數使 partition_function_name 將整個表或索引映射到單個分區。 只能使用 CREATE TABLE 或 CREATE INDEX 語句中指定的一個分區列。

  LEFT | RIGHT 指定當間隔值由 數據庫引擎 按升序從左到右排序時,boundary_value [ ,...n ] 屬於每個邊界值間隔的哪一側(左側還是右側)。 如果未指定,則默認值為 LEFT。

  示例:創建將用於Order表的分區函數

CREATE PARTITION FUNCTION Function_DateTime ( DATETIME )
AS RANGE RIGHT
FOR VALUES(‘2011-01-01‘, ‘2012-01-01‘, ‘2013-01-01‘, ‘2014-01-01‘)

  完成創建分區函數之後,可以通過以下SQL語句查看已創建的分區函數情況。

SELECT * FROM sys.partition_functions

2.4> 創建分區方案

  分區方案的作用是將分區函數生成的分區映射到文件組中去,分區方案是讓SQL Server將已分區的數據放在哪個文件組中。

  在當前數據庫中創建一個將已分區表或已分區索引的分區映射到文件組的方案。 已分區表或已分區索引的分區的個數和域在分區函數中確定。 必須首先在 CREATE PARTITION FUNCTION 語句中創建分區函數,然後才能創建分區方案。

  創建分區方案的Transact-SQL語法:

CREATE PARTITION SCHEME partition_scheme_name
AS PARTITION partition_function_name
[ ALL ] TO ( { file_group_name | [ PRIMARY ] } [ ,...n ] )
[ ; ]

  參數:

  partition_scheme_name:分區方案的名稱。 分區方案名稱在數據庫中必須是唯一的,並且符合標識符規則。

  partition_function_name:使用分區方案的分區函數的名稱。 分區函數所創建的分區將映射到在分區方案中指定的文件組。 partition_function_name 必須已經存在於數據庫中。 單個分區不能同時包含 FILESTREAM 和非 FILESTREAM 文件組。

  ALL:指定所有分區都映射到在 file_group_name 中提供的文件組,或映射到主文件組(如果指定了 [PRIMARY]。 如果指定了 ALL,則只能指定一個 file_group_name。

  file_group_name | [ PRIMARY ] [ ,...n]:指定用來持有由 partition_function_name 指定的分區的文件組的名稱。 file_group_name 必須已經存在於數據庫中。
  如果指定了 [PRIMARY],則分區將存儲於主文件組中。 如果指定了 ALL,則只能指定一個 file_group_name。 分區分配到文件組的順序是從分區 1 開始,按文件組在 [,...n] 中列出的順序進行分配。 在 [,...n] 中,可以多次指定同一個 file_group_name。 如果 n 不足以擁有在 partition_function_name 中指定的分區數,則 CREATE PARTITION SCHEME 將失敗,並返回錯誤。
  如果 partition_function_name 生成的分區數少於文件組數,則第一個未分配的文件組將標記為 NEXT USED,並且出現顯示命名 NEXT USED 文件組的信息。 如果指定了 ALL,則單獨的 file_group_name 將為該 partition_function_name 保持它的 NEXT USED 屬性。 如果在 ALTER PARTITION FUNCTION 語句中創建了一個分區,則 NEXT USED 文件組將再接收一個分區。 若要再創建一個未分配的文件組來擁有新的分區,請使用 ALTER PARTITION SCHEME。
  在 file_group_name[ 1,...n] 中指定主文件組時,必須像在 [PRIMARY] 中那樣分隔 PRIMARY,因為它是關鍵字。

  示例:創建將用於Order表的分區方案

CREATE PARTITION SCHEME Scheme_DateTime
AS PARTITION Function_DateTime
TO ( SECTION2010, SECTION2011, SECTION2012, SECTION2013, SECTION2014 )

  分區函數和分區方案創建之後,可以在數據庫的【存儲】中查看:

技術分享圖片

  通過可以通過以下SQL語句查看已創建的分區方案:

SELECT * FROM sys.partition_schemes

2.5> 創建分區表

技術分享圖片
CREATE TABLE [Order]
(
    OrderID INT IDENTITY(1,1) NOT NULL,
    UserID INT NOT NULL,
    TotalAmount DECIMAL(18,2) NULL,
    OrderDate DATETIME NOT NULL
) ON Scheme_DateTime ( OrderDate )
技術分享圖片

  這裏需要註意分區表不能再創建聚集索引,因為聚集索引可以將記錄在物理上順序存儲,而分區表是將數據存儲在不同的表中,這兩個概念是沖突的,所以在創建分區表時不能再創建聚集索引。

  完成Order表創建之後,查看表的屬性,可以看到Order表已經是分區表。

技術分享圖片

3. 操作分區表

3.1> Insert數據

技術分享圖片
USE [Northwind]
GO

INSERT INTO [dbo].[Order] ([UserID],[TotalAmount] ,[OrderDate]) VALUES (1 ,10.00 ,‘2009-10-20‘);
INSERT INTO [dbo].[Order] ([UserID],[TotalAmount] ,[OrderDate]) VALUES (1 ,20.50 ,‘2009-12-31‘);
INSERT INTO [dbo].[Order] ([UserID],[TotalAmount] ,[OrderDate]) VALUES (2 ,40.00 ,‘2010-01-20‘);
INSERT INTO [dbo].[Order] ([UserID],[TotalAmount] ,[OrderDate]) VALUES (3 ,40.00 ,‘2010-10-20‘);
INSERT INTO [dbo].[Order] ([UserID],[TotalAmount] ,[OrderDate]) VALUES (4 ,50.00 ,‘2011-10-20‘);
INSERT INTO [dbo].[Order] ([UserID],[TotalAmount] ,[OrderDate]) VALUES (5 ,60.00 ,‘2012-10-20‘);
INSERT INTO [dbo].[Order] ([UserID],[TotalAmount] ,[OrderDate]) VALUES (5 ,60.00 ,‘2012-10-20‘);
INSERT INTO [dbo].[Order] ([UserID],[TotalAmount] ,[OrderDate]) VALUES (6 ,70.00 ,‘2013-10-20‘);
INSERT INTO [dbo].[Order] ([UserID],[TotalAmount] ,[OrderDate]) VALUES (10 ,90.00 ,‘2014-10-20‘);
INSERT INTO [dbo].[Order] ([UserID],[TotalAmount] ,[OrderDate]) VALUES (9 ,100.00 ,‘2015-10-20‘);
GO
技術分享圖片

3.2> 查詢數據所在物理分區表

  在分區表中使用一般的SELECT語句無法知道數據是分別存放在哪幾個不同的物理表中,若要知道數據分別存放的物理表,可以使用$PARTITION函數,該函數可以調用分區函數並返回數據所在物理分區的編號。

  $PARTITION的語法:$PARTITION.分區函數名(表達式)

SELECT $PARTITION.Function_DateTime(‘2010-01-01‘)

技術分享圖片

  查詢結果分區函數返回為1,說明2010-01-01的數據會存放在第1個物理分區表中。

  使用$PARTITION函數可以具體知道每個物理分區表中存放了哪些記錄。

  查看物理分區表中存放的記錄:

SELECT * FROM [Order] WHERE $PARTITION.Function_DateTime(OrderDate) = 1

技術分享圖片

SELECT $PARTITION.Function_DateTime(OrderDate) AS 分區編號, COUNT(1) AS 記錄數 
FROM [Order]
GROUP BY $PARTITION.Function_DateTime(OrderDate)

技術分享圖片

3.3> 修改分區表數據

UPDATE dbo.[Order] SET OrderDate=‘2015-01-01‘ WHERE OrderID = 3

技術分享圖片

技術分享圖片

4. 將普通表轉換為分區表

  一般的普通表都是在主鍵上建聚集索引,記錄的物理保存位置由主鍵決定。

  示例:創建一個Product普通表

技術分享圖片
CREATE TABLE Product
(
    ProductID INT IDENTITY(1,1) NOT NULL,
    ProductName VARCHAR(100) NOT NULL,
    UnitPrice DECIMAL(18,2) NULL,
    CreateDate DATETIME NOT NULL,
    CONSTRAINT PK_Product PRIMARY KEY CLUSTERED (ProductID)
)
技術分享圖片 技術分享圖片
USE [Northwind]
GO

INSERT INTO [dbo].[Product] ([ProductName],[UnitPrice],[CreateDate]) VALUES (‘LINQ to SQL‘ ,10 ,‘2012-01-01‘);
INSERT INTO [dbo].[Product] ([ProductName],[UnitPrice],[CreateDate]) VALUES (‘LINQ to XML‘ ,10 ,‘2012-12-01‘);
INSERT INTO [dbo].[Product] ([ProductName],[UnitPrice],[CreateDate]) VALUES (‘LINQ to Object‘ ,10 ,‘2013-02-01‘);
INSERT INTO [dbo].[Product] ([ProductName],[UnitPrice],[CreateDate]) VALUES (‘LINQ to ADO.NET‘ ,10 ,‘2014-01-02‘);
INSERT INTO [dbo].[Product] ([ProductName],[UnitPrice],[CreateDate]) VALUES (‘LINQ to Entity‘ ,10 ,‘2015-01-01‘);

GO
技術分享圖片

  查看表Product的屬性:

技術分享圖片

  查看表Product的索引,可以看到PK_Product為聚集索引。

技術分享圖片

  將普通表轉換為分區表的操作是先在普通表上刪除聚集索引,在創建一個新的聚集索引,在該聚集索引中使用分區方案。

  在SQL Server中,主鍵字段上默認創建聚集索引,刪除主鍵的聚集索引。

ALTER TABLE Product DROP CONSTRAINT PK_Product

  重新創建主鍵非聚集索引

ALTER TABLE Product ADD CONSTRAINT PK_Product PRIMARY KEY NONCLUSTERED (ProductID ASC)

  重新創建後的主鍵:

技術分享圖片

  創建使用分區方案的聚集索引:

CREATE CLUSTERED INDEX IX_CreateDate ON Product ( CreateDate )
ON Scheme_DateTime ( CreateDate )

  調整後的Product表屬性:

技術分享圖片

技術分享圖片

  調整後Product表記錄的物理保存情況:

技術分享圖片

5. 刪除(合並)一個分區表

  刪除2012-01-01的分區,修改分區函數:

ALTER PARTITION FUNCTION Function_DateTime() MERGE RANGE (‘2012-01-01‘)

  在修改了分區函數之後,與之關聯的分區方案也將同時自動調整。在執行了上面合並分區的函數之後,查看分區方案的Create腳本。

CREATE PARTITION SCHEME [Scheme_DateTime] AS PARTITION [Function_DateTime] TO ([SECTION2010], [SECTION2011], [SECTION2013], [SECTION2014])

  合並分區之後,被合並的分區記錄也將被重新分配物理保存位置。

技術分享圖片

6. 添加分區

  分區方案中指定的文件組個數比分區函數中指定的邊界數大1,為分區方案指定一個可用的文件組時,該分區方案並沒有立刻使用這個文件組,只是將文件組先備用著,等修改了分區函數之後分區方案才會使用這個文件組。如果分區函數沒有更改,分區方案中的文件組個數也不會更改。

  添加分區所需要使用到的文件組可以使用之前合並分區之後沒有再使用的SECTION2012,也可以新建文件組。

ALTER DATABASE [Northwind] ADD FILEGROUP [SECTION2015]
技術分享圖片
ALTER DATABASE [Northwind] ADD FILE 
( 
    NAME = N‘Northwind_Data_2015‘, 
    FILENAME = N‘F:\Database\Northwind\Northwind_Data_2015.ndf‘ , 
    SIZE = 5120KB , 
    FILEGROWTH = 1024KB 
) TO FILEGROUP [SECTION2015]
技術分享圖片

  為分區方案指定一個可用的文件組:

ALTER PARTITION SCHEME Scheme_DateTime NEXT USED [SECTION2015]

  修改分區函數,添加分區:

ALTER PARTITION FUNCTION Function_DateTime() SPLIT RANGE(‘2015-01-01‘)

  查看添加分區後的數據物理存儲:

技術分享圖片

Sql Server系列:分區表操作