SQL Server 大数据管理——表分区

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\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 ,
                    i.name IndexName
--,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.IndexName ,
        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')
ORDER BY cte.IndexName ,
        partition_number

可以看到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中。

如果喜欢,可以扫码关注SQL Server 公众号,将有更多精彩内容分享:

                                                                 

  • 4
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值