SQL Server2008及以上 表分區操作詳解


SQL Server 表分區之水平表分區

 轉自:https://www.cnblogs.com/Brambling/p/6766482.html

什么是表分區?

表分區分為水平表分區和垂直表分區,水平表分區就是將一個具有大量數據的表,進行拆分為具有相同表結構的若干個表;而垂直表分區就是把一個擁有多個字段的表,根據需要進行拆分列,然后根據某一個字段進行關聯。

 

表分區分為以下五個步驟:

1、創建文件組

2、創建數據文件

3、創建分區函數

4、創建分區方案

5、創建分區表

 

水平表分區

創建文件組:

語法:

-- 創建文件組語法
alter database <數據庫名> add filegroup <文件組名>
復制代碼
alter database Test add filegroup GroupOne

alter database Test add filegroup GroupTwo

alter database Test add filegroup GroupThree

alter database Test add filegroup GroupFour

alter database Test add filegroup GroupFive
復制代碼

創建數據文件到指定文件組:

語法:

復制代碼
-- 創建數據文件到指定文件組語法

alter database <數據庫名稱> add file <文件屬性> to filegroup <文件組名稱>

<文件屬性>
(
    name=文件的邏輯名稱,
    filename=文件的物理名稱,
    size=文件初始大小,
    filegrowth=文件自動增長量(數值或百分比),
    maxsize=文件增長的最大值
)
復制代碼
復制代碼
alter database Test add file
(
    name=N'OneFile',
    filename=N'D:\DataDB\OneFile.mdf',
    size=3MB,
    filegrowth=10%,
    maxsize=unlimited    -- 無限大小
)
to filegroup GroupOne

alter database Test add file
(
    name=N'TwoFile',
    filename=N'D:\DataDB\TwoFile.mdf',
    size=3MB,
    filegrowth=10%,
    maxsize=unlimited    -- 無限大小
)
to filegroup GroupTwo

alter database Test add file
(
    name=N'ThreeFile',
    filename=N'D:\DataDB\ThreeFile.mdf',
    size=3MB,
    filegrowth=10%,
    maxsize=unlimited    -- 無限大小
)
to filegroup GroupThree

alter database Test add file
(
    name=N'FourFile',
    filename=N'D:\DataDB\FourFile.mdf',
    size=3MB,
    filegrowth=10%,
    maxsize=unlimited    -- 無限大小
)
to filegroup GroupFour

alter database Test add file
(
    name=N'FiveFile',
    filename=N'D:\DataDB\FiveFile.mdf',
    size=3MB,
    filegrowth=10%,
    maxsize=unlimited    -- 無限大小
)
to filegroup GroupFive
復制代碼

創建分區函數:

創建一個分區函數,創建分區函數的目的是告訴 SQL Server 以什么方式對分區表進行分區。

語法:

create partition function    -- 創建分區函數
Part_Fun(int)    -- 分區函數名(分區列類型)
as range [left/right]    -- 左置/右置,即邊界值的存儲位置,如果設置為右置,邊界值存到下一個表
for values ('1000','2000','3000','4000','5000')        -- 設置每個分區表的邊界值 
create partition function    
Part_Fun(int)    
as range right    
for values ('1000','2000','3000','4000','5000')        

刪除分區函數:

--刪除分區函數語法
drop partition function <分區函數名>

--刪除名為 Part_Fun 的分區函數
drop partition function Part_Fun

PS:只有當分區函數沒有應用到分區方案中時,指定的分區函數才能被刪除。

創建分區方案:

分區方案的作用是將分區函數生成的分區映射到文件組中去。分區函數的作用是告訴SQL Server,如何將數據進行分區,而分區方案的作用則是告訴 SQL Server 將已分區的數據放在哪個文件組中。

語法:

--創建分區方案語法
create partition scheme        -- 創建分區方案
<分區方案名稱>    -- 分區方案名稱
as partition <分區函數名稱>    -- 指定分區函數名稱
to (文件組名稱,,,,)    -- 指定分區函數划分出來的數據對應存放的文件組
create partition scheme        -- 創建分區方案
Part_Plan    -- 分區方案名稱
as partition Part_Fun    -- 分區函數名稱
to ('GroupOne','GroupTwo','GroupThree','GroupFour','GroupFive') -- 分區文件組

一執行,結果報錯了。

不對呀,我明明建立的是五個分區文件組,分區函數也是分為五份的啊。其實這里的意思應該就是后續數據的問題了,首先不可能保證這個表永遠就 5000 條數據的,所以他在這里的意思就是后續數據存儲的文件組。這里我把后續數據放在最后一個文件組里面。

create partition scheme        -- 創建分區方案
Part_Plan    -- 分區方案名稱
as partition Part_Fun    -- 分區函數名稱
to ('GroupOne','GroupTwo','GroupThree','GroupFour','GroupFive','GroupFive') -- 分區文件組

刪除分區方案:

--刪除分區方案語法
drop partition scheme<分區方案名稱>

--刪除名為 Part_Plan 的分區方案
drop partition scheme Part_Plan

PS:當沒有分區表引用該分區方案時,才能對其進行刪除。

創建分區表:

語法:

--創建分區表語法
create table <表名>    -- 表名稱
(
    column1        int        not null  primary key nonclustered,    -- 字段名稱、字段類型、是否可空、主鍵約束、非聚集索引
    column2        int        not null    
) on <分區方案名>(分區列名)        -- 分區方案的名稱(指定要依據分區的列名)
create table US_Info
(
    ID        int        not null    primary key identity(1,1),
    Name    nvarchar(32)    null,
    CreateTime    nvarchar(32)    null
)on Part_Plan(ID)

PS:如果在表中創建有主鍵、唯一索引、聚集索引,則分區依據列必須為該列之一。即分區依據列必須建立在主鍵、唯一索引、聚集索引之上。

創建分區索引:

語法:

--創建分區索引語法
create [ unique [ clustered | nonclustered ] ]  -- unique 唯一    clustered 聚集    nonclustered 非聚集
index <索引名稱>    -- 指定索引名稱
on <表名>(列名)        -- 指定表名(指定列名)
on <分區方案名>(分區依據列名)    -- 分區方案名稱(分區依據列名)
create nonclustered  
index Part_Non_Name    
on US_Info(Name)        
on Part_Plan(ID)    

在表 US_Info 中插入5000條數據:

復制代碼
declare @I    int
set @I=1
while(@I<=5000)
begin
    insert into US_Info(Name,CreateTime)
    values('名稱'+convert(nvarchar,@I),Convert(nvarchar,GETDATE(),121))
    set @I=@I+1
end

select * from US_Info
復制代碼

查詢指定值位於數據表哪個分區中:

-- 查詢指定值位於數據表哪個分區中

select $partition.Part_Fun('3050')    -- 返回 4,表示位於第四個分區中

查詢分區表中,每個分區存在的數據的行數:

--查看分區表中,每個分區存在的數據的行數

select $partition.Part_Fun(ID) as Part_Num,count(1) as R_Count
from US_Info
group by  $partition.Part_Fun(ID)

查詢指定分區中的數據:

-- 查詢指定分區中的數據

select * from US_Info 
where $partition.Part_Fun(ID)=3

 

拆分分區:

在分區函數中新增一個邊界值,即可將 1 個分區拆分為 2 個。

--將第 3 個分區拆分為 2 個分區
alter partition function Part_Fun()
split range(N'2500')  

一執行,報錯了,拆分不了,因為前面我們已經用分區函數指定了分區和文件組,那就要先添加一個文件組。

為分區方案指定下一個文件組:

復制代碼
-- 添加一個文件組 GroupSix
alter database Test add filegroup GroupSix

-- 添加一個數據文件 
alter database Test add file
(
    name=N'SixFile',
    filename=N'D:\DataDB\SixFile.mdf',
    size=3MB,
    filegrowth=10%,
    maxsize=unlimited    -- 無限大小
)
to filegroup GroupSix

-- 為分區方案指定下一個文件組

alter partition scheme Part_Plan  -- 分區方案名稱
next used GroupSix    -- 下一個文件組名稱
復制代碼

然后再來對分區進行拆分:

--將第 3 個分區拆分為 2 個分區
alter partition function Part_Fun()    -- 分區函數
split range        -- 分割界限
(N'2500')  -- 分區界限值

合並分區:

與拆分分區相反,去除一個邊界值即可。

-- 將第 3 個分區與第 4 個分區合並
alter partition function Part_Fun()     -- 分區函數
merge range        -- 合並界限
(N'2500')  -- 合並界限值

復制分區表中的數據到普通表:

復制分區表中的數據到普通表需要滿足以下條件:

數據表的結構必須相同,即字段數量、字段類型等,字段與字段之間必須對應。

兩個表必須位於同一文件組,所以創建普通表的時候就需要指定文件組。

create table US_Info_back        -- 創建普通表的表名
(
    ID        int        not null    primary key identity(1,1),    -- 列定義
    Name    nvarchar(32)    null,
    CreateTime    nvarchar(32)    null
)on GroupThree    -- 指定文件組

將分區表中的數據復制到普通表:

復制代碼
-- 將分區表 US_Info 中的第 3 個分區的數據復制到普通表 US_Info_back 中

alter table US_Info 
switch partition 3 
to US_Info_back

select * from US_Info_back
復制代碼

將普通表中的數據復制到分區表:

--將普通表 US_Info_back 中的數據復制到分區表 US_Info 中的第 6 個分區

alter table US_Info_back    -- 普通表名
switch to US_Info    -- 分區表名
partition 6        -- 指定分區

PS:將普通表中的數據復制到分區表時,需要先刪除分區表的索引。

將普通表轉換為分區表:

當數據庫已經存在數據的時候,就不能像上面那樣直接建立分區表了,只能將普通表轉換為分區表,只需在該普通表上創建一個聚集索引,並在該聚集索引中使用分區方案即可。

如果是已經存在的聚集索引,那么需要刪除然后重新建立,並使用分區方案。

現在我有一個現成的表 UserInfo,因為它存在一個主鍵,而建立主鍵時,系統會自動為主鍵列添加聚集索引,因為這個聚集索引沒法刪除,所以我現在要先刪除這個主鍵,然后重新建立一個主鍵,並設置為非聚集索引,然后為主鍵創建一個聚集索引(會覆蓋非聚集索引),並使用分區方案指定分區列即可。

復制代碼
-- 根據 指定表名 查詢 表的約束
exec sp_helpconstraint UserInfo      -- UserInfo 表名

-- 根據指定主鍵約束名刪除指定表的主鍵約束
alter table UserInfo drop constraint PK__UserInfo__5A2040BBA6D6767A 

-- 添加主鍵約束,但設置為非聚集索引
alter table UserInfo add constraint PK__UserInfo__5A2040BBA6D6767A primary key nonclustered (U_Id)


-- 添加一個聚集索引,並使用分區方案指定分區的列

create clustered index CLU_StuNo -- 索引名稱
on UserInfo(U_Id)  -- 指定添加索引的表(添加索引的列)
on Part_Plan(U_Id)        -- 分區方案名稱(分區依據的列)
復制代碼

為這個表也插入5000條數據,看看效果:

復制代碼
declare @I    int
select @I=U_Id from UserInfo order by U_Id desc
while(@I<=5000)
begin
    insert into UserInfo(U_No,U_Name,U_Pwd)
    values('demo'+convert(nvarchar,@I),'demo'+convert(nvarchar,@I),'40D1C69C7B86064EA140C13CE8ED0E15')
    set @I=@I+1
end

select * from UserInfo
go
復制代碼

查看分區表中,每個分區存在的數據的行數:

--查看分區表中,每個分區存在的數據的行數
select $partition.Part_Fun(U_Id) as Part_Num,count(1) as R_Count
from UserInfo 
group by  $partition.Part_Fun(U_Id)
order by Part_Num 

 

查看數據庫分區信息 SQL(復制來的):

復制代碼
SELECT OBJECT_NAME(p.object_id) AS ObjectName,
      i.name                   AS IndexName,
      p.index_id               AS IndexID,
      ds.name                  AS PartitionScheme,   
      p.partition_number       AS PartitionNumber,
      fg.name                  AS FileGroupName,
      prv_left.value           AS LowerBoundaryValue,
      prv_right.value          AS UpperBoundaryValue,
      CASE pf.boundary_value_on_right
            WHEN 1 THEN 'RIGHT'
            ELSE 'LEFT' END    AS Range,
      p.rows AS Rows
FROM sys.partitions                  AS p
JOIN sys.indexes                     AS i
      ON i.object_id = p.object_id AND i.index_id = p.index_id
JOIN sys.data_spaces                 AS ds
      ON ds.data_space_id = i.data_space_id
JOIN sys.partition_schemes           AS ps
      ON ps.data_space_id = ds.data_space_id
JOIN sys.partition_functions         AS pf
      ON pf.function_id = ps.function_id
JOIN sys.destination_data_spaces     AS dds2
      ON dds2.partition_scheme_id = ps.data_space_id AND dds2.destination_id = p.partition_number
JOIN sys.filegroups                  AS fg
      ON fg.data_space_id = dds2.data_space_id
LEFT JOIN sys.partition_range_values AS prv_left
      ON ps.function_id = prv_left.function_id AND prv_left.boundary_id = p.partition_number - 1
LEFT JOIN sys.partition_range_values AS prv_right
      ON ps.function_id = prv_right.function_id AND prv_right.boundary_id = p.partition_number 
WHERE OBJECTPROPERTY(p.object_id, 'ISMSShipped') = 0
UNION ALL
SELECT
      OBJECT_NAME(p.object_id)    AS ObjectName,
      i.name                      AS IndexName,
      p.index_id                  AS IndexID,
      NULL                        AS PartitionScheme,
      p.partition_number          AS PartitionNumber,
      fg.name                     AS FileGroupName,  
      NULL                        AS LowerBoundaryValue,
      NULL                        AS UpperBoundaryValue,
      NULL                        AS Boundary, 
      p.rows                      AS Rows
FROM sys.partitions AS p
JOIN sys.indexes AS i ON i.object_id = p.object_id AND i.index_id = p.index_id
JOIN sys.data_spaces AS ds ON ds.data_space_id = i.data_space_id
JOIN sys.filegroups AS fg ON fg.data_space_id = i.data_space_id
WHERE OBJECTPROPERTY(p.object_id, 'ISMSShipped') = 0
ORDER BY ObjectName,IndexID,PartitionNumber
復制代碼

 

參考:

http://www.cnblogs.com/knowledgesea/p/3696912.html

http://blog.csdn.net/lgb934/article/details/8662956


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM