zoukankan      html  css  js  c++  java
  • SQL Server 大数据管理——表分区

    背景:

    在前面两篇博文《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 estPartion est2015.ndf'
    ,size=1mb
    ,filegrowth=1mb)
    to filegroup test2015;
    alter database test
    add file(name='test2016'
    ,filename='D:DB estPartion est2016.ndf'
    ,size=1mb
    ,filegrowth=1mb)
    to filegroup test2016;
    alter database test
    add file(name=N'test2017'
    ,filename=N'D:DB estPartion est2017.ndf'
    ,size=1mb
    ,filegrowth=1mb)
    to filegroup test2017
    alter database test
    add file(name=N'test2018'
    ,filename=N'D:DB estPartion est2018.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 estPartion est2019.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中
    ---------------------
    作者:三空道人
    来源:CSDN
    原文:https://blog.csdn.net/zhoujunah/article/details/79744590 

  • 相关阅读:
    51 Nod 1086 多重背包问题(单调队列优化)
    51 Nod 1086 多重背包问题(二进制优化)
    51 Nod 1085 01背包问题
    poj 2559 Largest Rectangle(单调栈)
    51 Nod 1089 最长回文子串(Manacher算法)
    51 Nod N的阶乘的长度 (斯特林近似)
    51 Nod 1134 最长递增子序列(经典问题回顾)
    51 Nod 1020 逆序排列
    PCA-主成分分析(Principal components analysis)
    Python中cPickle
  • 原文地址:https://www.cnblogs.com/keepdoit/p/10867541.html
Copyright © 2011-2022 走看看