我们知道很多事情都存在一个分治的思想,同样的道理我们也可以用到数据表上,当一个表很大很大的时候,我们就会想到将表拆
分成很多小表,查询的时候就到各个小表去查,最后进行汇总返回给调用方来加速我们的查询速度,当然切分可以使用横向切分,纵向
切分,比如我们最熟悉的订单表,通常会将三个月以外的订单放到历史订单表中,这里的三个月就是将订单表进行切分的依据。
好了,分区表的好处我想大家都很清楚了,下面我们看看如何实现。
一:分区表
这里我们做个例子,创建一个test数据库,表名为shop,以createtime作为分区依据。
1:确定分区依据
怎么分区的话,这个要看具体业务逻辑了,你可以按照时间,地区,求模等等都可以。
2:创建文件组
既然是文件组,肯定是对文件进行分类管理的,默认情况下就一个mdf和ldf文件,当所有的数据都挤压在mdf上,确实不是一个
很好的事情,降低我们的查询速度,当用到文件组的时候就可以创建多个ndf来分摊mdf中的数据,甚至还可以将ndf分摊到几个磁盘
上,充分利用服务器多核处理能力,说了这么多,我们看看sql语句咋搞,这里我创建四个文件组,分别存放2013之前,2013,2014
和2014年之后的数据。
1 alter database Test add filegroup Before2013 2 alter database Test add filegroup T2013 3 alter database Test add filegroup T2014 4 alter database Test add filegroup After2014
3:创建文件
根据上面在文件组上的概述,文件的作用大家都知道了,这里我们要做的是,将次文件.ndf附加到文件组上,因为我创建了4个文件组,
所以我也创建4个文件分别存放在这4个文件组中。
1 alter database Test add file 2 (Name=N'Before2013',filename='D:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\Before20131.ndf',size=5mb,maxsize=100Mb,filegrowth=5mb) 3 to filegroup Before2013 4 alter database Test add file 5 (Name=N'T2013',filename='D:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\T20131.ndf',size=5mb,maxsize=100Mb,filegrowth=5mb) 6 to filegroup T2013 7 alter database Test add file 8 (Name=N'T2014',filename='D:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\T20141.ndf',size=5mb,maxsize=100Mb,filegrowth=5mb) 9 to filegroup T2014 10 alter database Test add file 11 (Name=N'After2014',filename='D:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\After20141.ndf',size=5mb,maxsize=100Mb,filegrowth=5mb) 12 to filegroup After2014
4:编写分区函数
刚才也说了,我们是按照时间进行切分的,将数据表数据分成:
① 2013年之前
② 2013-2014
③ 2014-2015
④ 2015之后
既然都知道依据了,我们分区函数也方便写了。
1 create partition function RangeTime (datetime) 2 as range left for values ('2012-12-31','2013-12-31','2014-12-31')
从上面的sql,我们可以看到三个点将时间轴分成了4段
第一:rangeTime 为分组函数名。
第二:left 其实就是当时间点在边界时到底属于左侧还是右侧,因为这里是left,所以属于左侧,如果是right关键词,那就属于右侧了。
5:编写分区方案
分区方案也就是将分区函数与文件组进行一个关联,刚才也说了,3个时间点将一个时间轴分成了4部分,刚好对应了4个文件组。
那么具体的sql写法如下:
1 create partition scheme RangeSchema_CreateTime 2 as partition RangeTime 3 to (before2013,T2013,T2014,after2014)
6:创建分区表
跟普通表创建有点不一样,分区表的创建还需要指定这个分区需要使用哪个分区方案下的分区字段,那么这里就是RangeSchema_CreateTime
中的CreateTime字段。
1 create table Shop 2 ( 3 ID varchar(50), 4 ShopName varchar(50), 5 CreateTime datetime 6 ) on RangeSchema_CreateTime(CreateTime)
这里要注意,如果在创建表的时候指定了ID为主键的话,这个时候需要指定ID为分区字段,否则会报错的。
这时候可以在不要主键的情况下先创建表,然后再指定ID为主键。
7:插入测试数据并统计
这里我先插入10w条数据,然后来看看数据在各个分区的情况。‘
<1>插入数据
declare @i int
set @i = 1
while @i < 100000
begin insert into equipment_n values(@i,dateadd(dd,datediff(dd,'2012-01-01','2015-01-30')*RAND(),'2012-01-01'),1,@i+1,@i+2,@i+3)
set @i = @i +1
end
<2> 统计每个分区的数据量
这里主要有一个查询分区的关键字“$partition”,非常的有用。
select $partition.RangeTime(operaDate) as number, COUNT(*) as count
from equipment_n group by $partition.RangeTime(operaDate)
好了,到这个我们通过sql语句来实现分区表就已经完成了。
二:使用管理界面创建分区表
1:首先我们创建test1数据库和shop表
2:创建文件组和文件
3:创建分区
①:右键Shop表,弹出菜单中选择 “存储” => "创建分区"
②:创建“分区函数”名 和 “分区方案”名。
③:创建分区映射,也就是将”分区函数“和“文件组”进行关联。
④: 最后我们可以看一下界面给我生成的分区函数以及分区方案,蛮有意思的。
1 USE [Test1] 2 GO 3 BEGIN TRANSACTION 4 CREATE PARTITION FUNCTION [MyRangeCreatTime](datetime) AS RANGE LEFT FOR VALUES (N'2012-12-31T00:00:00', N'2013-12-31T00:00:00', N'2014-12-31T00:00:00') 5 6 7 CREATE PARTITION SCHEME [MySchemeCreateTime] AS PARTITION [MyRangeCreatTime] TO ([Before2013], [T2013], [T2014], [After2014]) 8 9 10 ALTER TABLE [dbo].[Shop] DROP CONSTRAINT [PK__Shop__3214EC277F60ED59] 11 12 13 ALTER TABLE [dbo].[Shop] ADD PRIMARY KEY NONCLUSTERED 14 ( 15 [ID] ASC 16 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 17 18 19 CREATE CLUSTERED INDEX [ClusteredIndex_on_MySchemeCreateTime_635288828144372217] ON [dbo].[Shop] 20 ( 21 [CreateTime] 22 )WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [MySchemeCreateTime]([CreateTime]) 23 24 25 DROP INDEX [ClusteredIndex_on_MySchemeCreateTime_635288828144372217] ON [dbo].[Shop] WITH ( ONLINE = OFF ) 26 27 28 29 30 COMMIT TRANSACTION
从图中可以看到生成好的分区函数名”[MyRangeCreatTime]“ 和分区架构名“[MySchemeCreateTime]”,最后我们执行下该sql就ok了。
⑤ 插入测试数据并进行简单的测试
这里测试下“2013-1-1”是在哪个分区下。
总结一下可能用到的所有sql语句:
1,新建默认的 filegroup
alter database Test add filegroup Before2013
2, 新建默认的 file
alter database Test add file
(Name=N'Before2013',filename='D:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\Before20131.ndf',size=5mb,maxsize=100Mb,filegrowth=5mb)
to filegroup Before2013
3,新建分区函数
create partition function RangeTime (datetime) as range left for values ('2012-12-31','2013-12-31','2014-12-31')
4,新建分区方案
create partition scheme RangeSchema_CreateTime as partition RangeTime to (before2013,T2013,T2014,after2014)
5,新建表
create table equipment_n
(
[dataId] [int] NOT NULL,
[operaDate] datetime NULL,
[eqId] [int] NULL,
[l1] [varchar](30) NULL,
[l2] [varchar](30) NULL,
[lc] [varchar](30) NULL,
) on RangeSchema_CreateTime(operaDate)
6, 自动添加数据
declare @i int
set @i = 4
while @i < 1000
begin insert into equipment_n ([operaDate]
,[eqId]
,[l1]
,[l2]
,[lc]) values(dateadd(dd,datediff(dd,'2012-01-01','2015-01-30')*RAND(),'2012-01-01'),1,@i+1,@i+2,@i+3)
set @i = @i +1
end
7, 查询分区表中数据分布情况
select $partition.RangeTime(operaDate) as number, COUNT(*) as count
from equipment_n group by $partition.RangeTime(operaDate)
8, 设置自增ID
alter table equipment_n drop column dataId alter table equipment_n add dataId int identity(1,1)
ALTER TABLE dbo.equipment_n ADD CONSTRAINT
PK_equipment_n PRIMARY KEY NONCLUSTERED
(
dataId
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
9, 定制计划
DECLARE @maxValue INT,
@secondMaxValue INT,
@differ INT,
@fileGroupName VARCHAR(200),
@fileNamePath VARCHAR(200),
@fileName VARCHAR(200),
@sql NVARCHAR(1000)
if(MONTH(GETDATE()) != '12')--计划每月执行,如果是12月则可以更新分局
begin
--生成新的文件组
SET @fileGroupName='IN_'+ convert(varchar(4),(YEAR(GETDATE())+1))
PRINT @fileGroupName
SET @sql='ALTER DATABASE [iom_db] ADD FILEGROUP '+@fileGroupName
PRINT @sql
EXEC(@sql)
--新建文件
SET @fileNamePath='C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA'
+ @fileGroupName +'.NDF'
SET @fileName=N'File'+convert(varchar(4),(YEAR(GETDATE())+1))
SET @sql='ALTER DATABASE [iom_db] ADD FILE (NAME='''+@fileName+''',FILENAME=N'''+@fileNamePath+''') TO FILEGROUP'+' '+@fileGroupName
PRINT @sql
PRINT 1
EXEC(@sql)
PRINT 2
--修改分区方案,用一个新的文件组用于存放下一新增的数据
SET @sql='ALTER PARTITION SCHEME [RangeSchema_CreateTime] NEXT USED'+' '+@fileGroupName
EXEC(@sql)
PRINT 3
ALTER PARTITION FUNCTION RangeTime() --分区函数
SPLIT RANGE (convert(datetime, convert(varchar(4),(YEAR(GETDATE())+1))+'-12-31 00:00:00.000'))
end