目录
前言
什么是表分区?
为什么要表分区?
什么时候需要表分区?
为什么选择Linux版SqlServer?
是否支持EF Core?
项目案例说明
编写SQL脚本
第一步、创建数据库Demo
第二步、创建文件组和分区文件
第三步、创建分区函数
第四步、创建分区架构
第五步、创建分区表
检验分区是否成功
当您找到这篇教程的时候,您已经被数据架构玩得头昏脑涨了,所以在进行教程之前,我先解答大家几个疑问:
通俗易懂的说,就是将一个数据表根据某字段的一定规则分为多个文件进行存储。
例如:有一个用户数据表Users,数据表有主键ID,ID为1~1000000的存储在数据文件A,ID为1000001~2000000的存储在数据文件B,依此类推。
当表数据规模非常庞大的时候,各种维护难题都会出现。以下是表分区的优势:
1、改善查询性能:对分区对象的查询可以仅搜索自己关心的分区,提高检索速度。
2、增强可用性:如果表的某个分区出现故障,表在其他分区的数据仍然可用;
3、维护方便:如果表的某个分区出现故障,需要修复数据,只修复该分区即可;
4、均衡I/O:可以把不同的分区映射到磁盘以平衡I/O,改善整个系统性能。
表的大小超过1GB(也有说法是2GB,但我建议是1GB,因为项目发展快速的情况下,表容量达到1GB后,距离2GB仅需要很短的运营时间)
理由很简单,需要用到表分区的项目基本是大型项目,例如:美团、拼多多、淘宝、唯品会等,而大型项目一定会用到微服务,微服务强烈推荐使用Linux系统,所以SqlServer也用Linux啦~
什么?我用C#开发的才选用SqlServer的,C#怎么运行在Linux?这里特别强调一下,.Net Core已经发展几年了,可运行于Linux,且运行效率超Java很多,且.Net Core非常适用于微服务。
很遗憾告诉您,当您选用微服务和表分区的时候,务必放弃EF Core,原因如下:
1、EF Core运行效率不如ado.net(虽然EF Core大大提高了开发速度),做表分区本身就是追求极致的运行效率
2、表分区不支持Code First,既然不支持Code First,那还要EF Core干嘛?
为了更好的编写教程,这里直接使用一个案例:我们即将设计一个数据库表Users,该表数据量可能达到100,000,000行,该表主键名称为Guid,类型uniqueidentifier,实际上该主键也是一个GUID(全局唯一标识符)。然后我们将这个表分为256分文件,预设每个文件存储数据100,000,000/256=390,625行。如果单独从一个100,000,000行的数据文件里的数据查找一个数据,效率太低了,但如果从一个只有390,625行的数据分区文件里查询一个数据,效率就很高了。
create database Demo
declare @c0 int
declare @c1 int
declare @c0_s varchar(1)
declare @c1_s varchar(1)
declare @c_s varchar(3)
declare @hex CHAR(16)
SET @hex = '0123456789ABCDEF'
--从00到FF轮询创建文件组名和分区文件名,后缀都为十六进制值00至FF,一共产生256个文件和分组
set @c0=0
while @c0<16
begin
set @c0_s=SUBSTRING(@hex, (@c0%16)+1, 1)
set @c1=0
while @c1<16
begin
set @c1_s=SUBSTRING(@hex, (@c1%16)+1, 1)
set @c_s=@c0_s+@c1_s
--创建文件组
exec('alter database Demo add filegroup FG_Users'+@c_s)
--创建分区文件
exec('alter database Demo add file (name=''F_Users'+@c_s+''',filename=''/data/mssql/demo/F_Users'+@c_s+'.ndf'',size=1mb,filegrowth=1mb) to filegroup FG_Users'+@c_s)
set @c1=@c1+1
end
set @c0=@c0+1
end
案例里的分区文件夹/data/mssql/demo/,需在linux下将所有者修改mssql。
执行命令:chown mssql /data/mssql/demo
--创建GUID分割列表,格式为00000000-0000-0000-0000-010000000000,00000000-0000-0000-0000-020000000000,...,00000000-0000-0000-0000-ff0000000000
--由于将表分割为256份,所以一共有255个分割GUID(没有00000000-0000-0000-0000-000000000000)
declare @guid_items varchar(max)
set @c0=0
while @c0<16
begin
set @c0_s=SUBSTRING(@hex, (@c0%16)+1, 1)
set @c1=0
while @c1<16
begin
set @c1_s=SUBSTRING(@hex, (@c1%16)+1, 1)
set @c_s=@c0_s+@c1_s
if @c0=0 and @c1=0
begin
end
else begin
if @c0=0 and @c1=1
begin
set @guid_items='''00000000-0000-0000-0000-'+@c0_s+@c1_s+'0000000000'''
end
else begin
set @guid_items= @guid_items+',''00000000-0000-0000-0000-'+@c0_s+@c1_s+'0000000000'''
end
end
set @c1=@c1+1
end
set @c0=@c0+1
end
--创建分区函数
if exists( select 1 from sys.partition_functions where name = 'fn_users_partition' )
begin
drop partition function fn_users_partition
end
exec('create partition function fn_users_partition(uniqueidentifier) as range left for values('+@guid_items+')')
--创建分区文件组名列表,格式为FG_Users00,FG_Users01,FG_Users02,...,FG_UsersFF
--每个分区文件组对应一个分区
declare @group_items varchar(max)
set @c0=0
while @c0<16
begin
set @c0_s=SUBSTRING(@hex, (@c0%16)+1, 1)
set @c1=0
while @c1<16
begin
set @c1_s=SUBSTRING(@hex, (@c1%16)+1, 1)
set @c_s=@c0_s+@c1_s
if @c0=0 and @c1=0
begin
set @group_items=@group_name+@c_s
end
else begin
set @group_items=@group_items+','+@group_name+@c_s
end
set @c1=@c1+1
end
set @c0=@c0+1
end
--创建分区架构
if exists( select * from sys.partition_schemes where name = 'sch_users_partition' )
begin
drop partition scheme sch_users_partition
end
exec('create partition scheme sch_users_partition as partition fn_users_partition to ('+@group_items+')')
create table Users(
[Guid] uniqueidentifier rowguidcol constraint PK_GUID primary key default(newid()),
[Time] smalldatetime not null default(getdate())
) on sch_users_partition([Guid])
到这里,表分区已结束!
insert Users ([Guid]) values (newid())
insert Users ([Guid]) values (newid())
insert Users ([Guid]) values (newid())
insert Users ([Guid]) values (newid())
insert Users ([Guid]) values (newid())
go
select *, $PARTITION.fn_users_partition([Guid]) AS 数据所在分区 from Users
还有另一种检验方式,当您插入大量数据的时候,例如循环插入10,000,000数据(测试时建议启动事务插入,不然太久了),观察分区文件大小变化。