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 

  • 相关阅读:
    windows cmd 中获取当前时间并输出此时间
    使用windows批处理来让git每日自动更新代码
    拒绝垃圾文章 在 ejabberd 中使用 MySQL
    IOS调试lldb命令常用,po,
    IOS 多语言本地化 完美解决方案
    [转]Xcode封装.Bundle文件
    百度地图SDK引用问题 Symbol(s) not found for architecture armv64
    loaded the "ViewController" nib but the view outlet was not set. 处理方式
    initWithFrame 和 initWithCoder
    使用IB_DESIGNABLE与IBInspectable特性实现可在视图编辑器的功能栏中设置
  • 原文地址:https://www.cnblogs.com/keepdoit/p/10867541.html
Copyright © 2011-2022 走看看