SQL Server 大數據管理——表分區

原文鏈接:https://blog.csdn.net/zhoujunah/article/details/79744590

背景:

在前面兩篇博文《SQL Server 大數據管理——數據歸檔(主文件備份)》、《SQL Server 大數據管理——數據歸檔(段落備份)》中,表分區在其中起到了主要作用,本文將介紹分區的實現及表分區的相關屬性和操作。
一.    創建分區文件組/文件

    --創建分區文件組
    alter database test add filegroup test2015
    alter database test add filegroup test2016
    alter database test add filegroup test2017
    alter database test add filegroup test2018
    --創建分區文件
    alter database test
        add file(name='test2015'
            ,filename='D:\DB\testPartion\test2015.ndf'
            ,size=1mb
            ,filegrowth=1mb)
            to filegroup test2015;
    alter database test
        add file(name='test2016'
            ,filename='D:\DB\testPartion\test2016.ndf'
            ,size=1mb
            ,filegrowth=1mb)
            to filegroup test2016;
    alter database test
    add file(name=N'test2017'
        ,filename=N'D:\DB\testPartion\test2017.ndf'
        ,size=1mb
        ,filegrowth=1mb)
    to filegroup test2017
    alter database test
    add file(name=N'test2018'
        ,filename=N'D:\DB\testPartion\test2018.ndf'
        ,size=1mb
        ,filegrowth=1mb)
    to filegroup test2018

二.    創建分區函數

    --創建分區函數
    create partition function f_TestDate(datetime)
    as range right for values('2016-01-01','2017-01-01','2018-01-01')

注意:

1.        F_TestDate 爲分區函數名,分區的字段是datetime類型

2.        Right 表示該分區包含右邊界值,上面分區函數會把數據分爲

    小於2016.1.1
    大於等於2016.1.1 且小於2017.1.1
    大於等於2017.1.1 且小於2018.1.1
    大於等於2018.1.1

四個分區,若把right換爲left,則分區變爲

    小於等於2016.1.1
    大於2016.1.1 且小於等於2017.1.1
    大於2017.1.1 且小於等於2018.1.1
    大於2018.1.1

三.    創建分區方案

    --創建分區方案
    create partition scheme s_TestDate
    as partition f_TestDate to (test2015,test2016,test2017,test2018)

注意:

1.        分區方案是建立在分區函數的基礎上的,所以先建立分區函數,再建立分區方案

2.        分區個數比分區邊界值多1

3.        本分區方案每個分區建在一個文件組上,當然也可以把所有分區建立在一個文件組上

    --創建分區方案,所有分區均建立在主文件組上
    create partition scheme s_TestDate
    as partition f_TestDate all to ([primary])

兩種方案的優劣待續……
四.    創建分區表

4.1  新建分區表

    create table tradelog
    (
        ID int,
        productID int,
        tradedate datetime
    ) on s_TestDate(tradedate)

注:創建分區表,用的是s_TestDate分區方案名稱
4.2  對已有表分區

若表上沒有聚集索引,可以通過創建聚集索引,對錶進行分區

    CREATE CLUSTERED INDEX [CLI_tn_TestDate] ON [dbo].[tradelog_noClusterIndex]
    (
        [tradedate]
    ) ON [s_TestDate]([tradedate])
     
    --如果不需要聚集索引,刪除聚集索引
    DROP INDEX [CLI_tn_TestDate] ON [dbo].[tradelog_noClusterIndex]

若表上已有聚集索引,刪除聚集索引,再通過上面腳本重建聚集索引。或者通過WITH(DROP_EXISTING=ON)重建聚集索引,腳本如下:

    CREATE CLUSTERED INDEX [CLI_tn_TestDate] ON [dbo].[tradelog_noClusterIndex]
    (
        [tradedate]
    )WITH (DROP_EXISTING = ON) ON [s_TestDate]([tradedate])

五.    增加分區

增加分區的方法是將某個現有的分區“拆分”爲兩個分區並重新定義新分區的邊界。

    --向分區表插入1000W行數據
    DECLARE @max AS INT, @rc AS INT;  
    SET @max = 10000000;  
    SET @rc = 1;  
    INSERT INTO tradelog(id,productID,tradedate) VALUES(1,1,'2014-01-01');  
    WHILE @rc * 2 <= @max  
    BEGIN  
        INSERT INTO dbo.tradelog(id,productID,tradedate) SELECT id + @rc,id + @rc+1,DATEADD(mi,id,tradedate) FROM dbo.tradelog;  
        SET @rc = @rc * 2;  
    END  
    INSERT INTO dbo.tradelog (id,productID,tradedate)
    SELECT id + @rc,id + @rc+1,DATEADD(mi,id,tradedate) FROM dbo.tradelog WHERE id + @rc <= @max;  
    go  
     
    --查看分區表的現狀
    ;with cte as
        (select
            object_id
            ,OBJECT_NAME(i.object_id) tableName
            ,i.index_id
            ,dds.partition_scheme_id
            ,dds.destination_id as partition_number
            ,fg.groupid
            ,fg.groupname
            ,f.fileid
            ,f.name
            ,f.filename
            --,p.partition_id
            --,p.rows
         from sys.destination_data_spaces dds,sys.indexes i,sys.sysfilegroups fg,sys.sysfiles f
         where dds.partition_scheme_id=i.data_space_id
            and dds.data_space_id=fg.groupid
            and fg.groupid=f.groupid
            )
    ,cte1 as(
        select
            ps.data_space_id as partition_scheme_id
            ,ps.name partiton_schemes_name
            ,pf.name partition_function_name
            ,pf.function_id
            --,prv.value AS BoundaryValue
        from sys.partition_schemes ps ,sys.partition_functions pf
        where ps.function_id=pf.function_id
            --and pf.function_id=prv.function_id
    )
    select cte.tableName,cte.groupname,cte.name,cte.filename
        ,cte.partition_number,cte1.partiton_schemes_name,cte1.partition_function_name,p.rows
        ,prv.boundary_id,prv.value BoundaryValue
    from cte
    inner join cte1    on cte.partition_scheme_id=cte1 .partition_scheme_id
    left join sys.partition_range_values prv on cte1.function_id=prv.function_id and cte.partition_number=prv.boundary_id
    left join sys.partitions  p on cte.object_id=p.object_id and cte.index_id=p.index_id and cte.partition_number=p.partition_number
     
    where
         cte.object_id=OBJECT_ID('dbo.tradelog','U')


可以看到tradelog表按交易時間列分爲4區,分區邊界值爲16、17、18三年的1月1日,其中

    16年以前的數據存在文件test2015上
    16年數據存在文件test2016上
    17年數據存在文件test2017上
    18年及以後的數據存在文件test2018上

現在增加一個分區,將2019以後的數據分開,或者說將原4分區以2019年1月1日爲分區邊界拆分爲兩個分區,具體腳本如下:

    --創建新分區文件組
    alter database test add filegroup test2019
    --創建新分區文件
    alter database test
        add file(name='test2019'
            ,filename='D:\DB\testPartion\test2019.ndf'
            ,size=1mb
            ,filegrowth=1mb)
            to filegroup test2019;
    alter partition scheme s_TestDate
    next used test2019
     
    alter partition function f_TestDate()
    split range('2019-01-01 0:00:00')

重新執行分區狀態查詢腳本,結果如下圖:


可以看到,源第4分區被拆分爲兩個分區,並且2019年以後的數據被移動到新的文件test2019上。

可以有這樣一個結論,新增分區後,新增的邊界值,到下一個分區邊界值之間的數據,將被移動到新的文件上,無論是拆分第1個分區,還是拆分中間的某個分區(如拆分第4個分區),如下圖:


六.    合併分區

減少分區的方法是將兩個分區的邊界“合併”成一個。 減少分區操作將重新填充一個分區而不對另一個分區進行分配。

    --分區合併
    alter partition function f_TestDate()
    merge range('2018-07-01 0:00:00')


分區合併的數據移動方向剛好和增加分區的方向相反,分區合併後,將合併分界點的後一個分區數據移動到前一個分區的文件中。這個結論在數據自動歸檔中將極爲有用,因爲數據歸檔最後一步是將合併後的空文件、文件組回收,這樣就可以確定回收的文件名
七.    分區數據移到普通表

    create table tradelog_partition1
    (
        ID int,
        productID int,
        tradedate datetime
    ) on test2015
    alter table tradelog switch partition 1 to tradelog_partition1

把分區表的某個分區數據轉移到普通表,要求

1.      普通表必須和對應的分區在同一個文件組下

2.      普通表和分區表結構相同,包括字段、數據類型、數據長度、索引等

分區表上在tradedate上有聚集索引,但普通表tradelog_partition1上沒有建聚集索引,執行上述腳本就會報如下錯誤:

 

八.    普通表數據移到某一分區

alter table tradelog_partition1 switch to tradelog partition 1

在tradelog_partition1的tradedate上創建聚集索引,重新執行上面的腳本,又報瞭如下錯誤

What happen??這是因爲分區1上有CHECK日期要在2014到2016之間,而tradelog_partition1上沒有這個檢查,所以,在表上加上如下檢查:

    ALTER TABLE dbo.tradelog_partition1
            ADD CONSTRAINT TradeDate_Switch_CHECK CHECK
                (TradeDate >= CONVERT(DATE,'2014-01-01') AND TradeDate < CONVERT(DATE,'2016-01-01')
                AND TradeDate IS NOT NULL);
    GO

再執行移動數據,數據又重新移回到分區1中

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章