对分区表,特别需要注意的是:
1、如果分区表,有一个聚集索引,当然肯定是包含了分区列,可以建立不包含分区列的唯一索引。
2、如果分区表,有一个主键聚集索引,那么建立不包含分区列的唯一索引,会报错。
3、如果这个表一开始是个普通表,先建立的唯一索引,那么再改造为分区表时,当然了,也就没有唯一索引报错的问题了。
但不管是上面的哪种情况,这个不包含分区列的唯一索引,都是个全局索引,如果进行了分区操作,那么这个唯一索引就会失效,必须要重建。
1、分区表提供了内建的方法,水平划分表和索引中的数据。水平分区是指每一个分区都有相同数量的列,只是减少了行的数量。分区使超大型表和索引的管理变的简单,减少加载时间,改善查询时间,允许更小的维护窗口。
--1.创建数据库
create database wc
on primary
(
name = wc_data,
filename = 'D:\wc_data.mdf'
)
log on
(
name = wc_log1,
filename = 'd:\wc_log1.ldf'
),
(
name = wc_log2,
filename = 'd:\wc_log2.ldf'
)
--2.增加文件组
alter database wc
add filegroup wc_fg1
alter database wc
add filegroup wc_fg2
alter database wc
add filegroup wc_fg3
alter database wc
add filegroup wc_fg4
--3.把文件添加到文件组中
alter database wc
add file
(
name = wc_fg1_1,
filename = 'd:\wc_fg1_1.ndf',
size = 1MB
)
to filegroup wc_fg1
alter database wc
add file
(
name = wc_fg2_1,
filename = 'd:\wc_fg2_1.ndf',
size = 1MB
)
to filegroup wc_fg2
alter database wc
add file
(
name = wc_fg3_1,
filename = 'd:\wc_fg3_1.ndf',
size = 1MB
)
to filegroup wc_fg3
alter database wc
add file
(
name = wc_fg4_1,
filename = 'd:\wc_fg4_1.ndf',
size = 1MB
)
to filegroup wc_fg4
--这个很重要
use wc
go
--4.创建分区函数
create partition function wcLeftRange(datetime)
as range left for values('2006-01-01','2007-01-01','2008-01-01')
create partition function wcRightRange(datetime)
as range right for values('2006-01-01','2007-01-01','2008-01-01')
--5.创建分区方案
create partition scheme wcLeftRangeScheme
as partition wcLeftRange
to (wc_fg1,wc_fg2,wc_fg3,wc_fg4)
--6.创建分区表
create table dbo.wcT
(wcId bigint not null,
wcV varchar(100) not null ,
wcDate datetime not null,
constraint pk_wcid_date
primary key(wcId,wcDate)
)
on wcLeftRangeScheme(wcDate)
insert into dbo.wcT(wcId,wcV,wcDate)
values(1,'2','2006-01-01 00:00:00'),
(2,'1','2005-12-31 23:59:59'),
(3,'2','2006-12-31 23:59:59'),
(4,'3','2007-01-01 00:00:00'),
(5,'4','2008-01-01 00:00:00'),
(6,'4','2008-12-31 23:59:59')
--7.显示每条数据所属分区号,从1开始计算
select *,
--$partition函数,后面是分区函数名称,列名称
$partition.wcLeftRange(wcDate) as partition
from wcT
--8.1再次增加文件组和文件
alter database wc
add filegroup wc_fg5
alter database wc
add file
(
name = wc_fg5_1,
filename = 'd:\wc_fg5_1.ndf',
size = 1MB
)
to filegroup wc_fg5
--8.2指定下一个要使用的分区文件组
alter partition scheme wcLeftRangeScheme
next used [wc_fg5]
--8.3定义一个新的边界值来创建一个新的分区
alter partition function wcLeftRange()
split range ('2009-01-01')
insert into wcT(wcId,wcV,wcDate)
values(7,'5','2008-12-31 23:59:59'),
(8,'6','2009-01-01 23:59:59')
--8.4移除一个分区,其实就是把2个分区合并成一个分区,行重新分配到目标分区
alter partition function wcLeftRange()
merge range ('2007-01-01')
--8.5新建一个历史表
create table wcThistory
(wcId bigint not null ,
wcV varchar(100) not null,
wcDate datetime not null,
constraint pk_wchistory
primary key (wcId,wcDate)
) on [wc_fg3]
--8.6把源表的第2个分区转到目标表
--要求:源表和目标表必须在同一个文件组上,且目标表必须为空
--当然,目标表也可以是分区表,也必须为空,且在同一个文件组上
alter table wcT
switch partition 2 to wcThistory
--9.显示分区表的分区信息
select *
from sys.partitions p
inner join sys.allocation_units au
on p.hobt_id = au.container_id
inner join sys.data_spaces ds
on ds.data_space_id = au.data_space_id
where p.object_id = 213575799
--10.删除分区函数,分区方案
drop partition scheme wcLeftRangeScheme
drop partition function wcLeftRange
在表已经存在的情况下,构建分区表,通过删除主键约束,重建主键约束,同时按照分区架构来建立聚集索引。当然,如果表本来就没有主键,只有一个聚集索引,那么可以直接删除聚集索引,然后在重建聚集索引时指定分区架构,其实就是索引分区,只不过这个索引里存储的是真正的表的数据。
--1.创建数据库
create database wc
on primary
(
name = wc_data,
filename = 'D:\wc_data.mdf'
)
log on
(
name = wc_log1,
filename = 'd:\wc_log1.ldf'
),
(
name = wc_log2,
filename = 'd:\wc_log2.ldf'
)
--2.增加文件组
alter database wc
add filegroup wc_fg1
alter database wc
add filegroup wc_fg2
alter database wc
add filegroup wc_fg3
alter database wc
add filegroup wc_fg4
--3.把文件添加到文件组中
alter database wc
add file
(
name = wc_fg1_1,
filename = 'd:\wc_fg1_1.ndf',
size = 1MB
)
to filegroup wc_fg1
alter database wc
add file
(
name = wc_fg2_1,
filename = 'd:\wc_fg2_1.ndf',
size = 1MB
)
to filegroup wc_fg2
alter database wc
add file
(
name = wc_fg3_1,
filename = 'd:\wc_fg3_1.ndf',
size = 1MB
)
to filegroup wc_fg3
alter database wc
add file
(
name = wc_fg4_1,
filename = 'd:\wc_fg4_1.ndf',
size = 1MB
)
to filegroup wc_fg4
--4.创建分区函数
use wc
go
create partition function wcLeftRange(datetime)
as range left for values('2006-01-01','2007-01-01','2008-01-01')
create partition function wcRightRange(datetime)
as range right for values('2006-01-01','2007-01-01','2008-01-01')
--5.创建分区方案
create partition scheme wcLeftRangeScheme
as partition wcLeftRange
to (wc_fg1,wc_fg2,wc_fg3,wc_fg4)
--6.1创建表,下面是把已经存在的表改为分区表,其实分区表说到底就是对聚集索引的分区,
--所以只要重建主键索引就可以了
create table dbo.wcT
(wcId bigint not null,
wcV varchar(100) not null ,
wcDate datetime not null,
constraint pk_wcid_date
primary key(wcId,wcDate)
)
--6.2添加数据
insert into dbo.wcT(wcId,wcV,wcDate)
values(1,'2','2006-01-01 00:00:00'),
(2,'1','2005-12-31 23:59:59'),
(3,'2','2006-12-31 23:59:59'),
(4,'3','2007-01-01 00:00:00'),
(5,'4','2008-01-01 00:00:00'),
(6,'4','2008-12-31 23:59:59')
--6.3现在需要把原表按照一个分区架构来分区
--6.3.1如果这么删除,会报错,因为这个索引正用于 PRIMARY KEY 约束的强制执行
drop index pk_wcid_date on dbo.wcT
--6.5.2重建聚集索引,操作失败,因为表'wcT'上已存在名称为'pk_wcid_date'的索引或统计信息。
create clustered index pk_wcid_date on wcT(wcId,wcDate)
on wcLeftRangeScheme(wcDate)
--6.3.3首先需要删除主键约束,应该这么写才是对的
alter table dbo.wcT
drop constraint pk_wcid_date
--6.3.4再次建立主键约束,指定创建聚集索引,同时指定分区架构
alter table dbo.wcT
add constraint pk_wcid_date primary key clustered (wcId,wcDate)
on wcLeftRangeScheme(wcDate)
--7.显示每条数据所属分区号,从1开始计算
select *,
--$partition函数,后面是分区函数名称,列名称
$partition.wcLeftRange(wcDate) as partition
from wcT
--8.1再次增加文件组和文件
alter database wc
add filegroup wc_fg5
alter database wc
add file
(
name = wc_fg5_1,
filename = 'd:\wc_fg5_1.ndf',
size = 1MB
)
to filegroup wc_fg5
--8.2指定下一个要使用的分区文件组
alter partition scheme wcLeftRangeScheme
next used [wc_fg5]
--8.3定义一个新的边界值来创建一个新的分区
alter partition function wcLeftRange()
split range ('2009-01-01')
insert into wcT(wcId,wcV,wcDate)
values(7,'5','2008-12-31 23:59:59'),
(8,'6','2009-01-01 23:59:59')
--8.4移除一个分区,其实就是把2个分区合并成一个分区,行重新分配到目标分区
alter partition function wcLeftRange()
merge range ('2007-01-01')
--8.5新建一个历史表
create table wcThistory
(wcId bigint not null ,
wcV varchar(100) not null,
wcDate datetime not null,
constraint pk_wchistory
primary key (wcId,wcDate)
) on [wc_fg3]
--8.6把源表的第2个分区转到目标表
--要求:源表和目标表必须在同一个文件组上,且目标表必须为空
--当然,目标表也可以是分区表,也必须为空,且在同一个文件组上
alter table wcT
switch partition 2 to wcThistory
--9.显示分区表的分区信息
select *
from sys.partitions p
inner join sys.allocation_units au
on p.hobt_id = au.container_id
inner join sys.data_spaces ds
on ds.data_space_id = au.data_space_id
where p.object_id = 213575799
--10.删除分区函数,分区方案
drop partition scheme wcLeftRangeScheme
drop partition function wcLeftRange
显示分区信息
select t.name as '表名',
i.type_desc as '索引类型',
case when is_primary_key = 1 then '主键'
else '非主键'
end as '键',
ds.name as '分区方案名称',
ds.type_desc '对象类型',
case when ds.is_default = 1 then '默认文件组'
else '非默认文件组'
end as '是否默认文件组',
pf.name '分区函数',
pf.type_desc '分区函数类型',
pf.fanout '函数创建的分区数',
case when pf.boundary_value_on_right =1
then '边界值包含在边界的right区域'
when pf.boundary_value_on_right = 0
then '边界值包含在边界值的left区域'
end as '边界说明',
prv.boundary_id as '边界id',
tp.name AS '边界值的数据类型',
prv.value '边界值'
from sys.tables t
inner join sys.indexes i
on i.object_id = t.object_id
inner join sys.data_spaces ds
on ds.data_space_id = i.data_space_id
inner join sys.partition_schemes ps
on ds.data_space_id = ps.data_space_id
inner join sys.partition_functions pf
on pf.function_id = ps.function_id
inner join sys.partition_range_values prv
on prv.function_id = pf.function_id
inner join sys.partition_parameters pp
on pp.function_id = prv.function_id
and pp.parameter_id = prv.parameter_id
inner join sys.types tp
on tp.system_type_id = pp.system_type_id
and tp.user_type_id = pp.user_type_id
where i.object_id = 213575799
and i.index_id = 1
显示表名、分区方案、分区函数、边界值、文件组等信息,还有存储在分区的记录数据
select *
from
(
select t.name as table_name,
p.partition_number,
p.rows,
ps.name as partition_scheme_name,
pf.name as partition_function_name,
tp.name as partition_boundary_value_type,
dsp.name as filegroup_name,
--prv.boundary_id,
--prv.value,
case when pf.boundary_value_on_right =0
and p.partition_number = 1
and p.partition_number = boundary_id
then '无穷小 < Value' + ' <= ' + convert(varchar(20),prv.value,120)
when pf.boundary_value_on_right = 0
and p.partition_number <> 1
and p.partition_number = boundary_id
then convert(varchar(20),
(select value
from sys.partition_range_values pfu
where pfu.function_id =prv.function_id and
pfu.boundary_id = prv.boundary_id -1
),120)
+ ' < Value' + ' <= ' + convert(varchar(20),prv.value,120)
when pf.boundary_value_on_right = 0
and p.partition_number = pf.fanout
and p.partition_number = prv.boundary_id + 1
then convert(varchar(20),prv.value,120) + ' < Value <= ' + '无穷大'
end as range_of_value
from sys.tables t
inner join sys.indexes i
on t.object_id = i.object_id
inner join sys.partitions p
on p.object_id = i.object_id
and p.index_id = i.index_id
inner join sys.allocation_units au
on au.container_id = p.hobt_id
inner join sys.data_spaces ds
on ds.data_space_id = i.data_space_id
inner join sys.partition_schemes ps
on ps.data_space_id = ds.data_space_id
inner join sys.partition_functions pf
on pf.function_id = ps.function_id
inner join sys.partition_range_values prv
on prv.function_id = pf.function_id
inner join sys.partition_parameters pp
on pp.function_id = prv.function_id
and pp.parameter_id = prv.parameter_id
inner join sys.types tp
on tp.system_type_id = pp.system_type_id
and tp.user_type_id = pp.user_type_id
inner join sys.data_spaces dsp
on au.data_space_id = dsp.data_space_id
where i.index_id = 1
and p.object_id = 213575799
)a
left join wcT w
on $partition.wcLeftRange(wcDate) = a.partition_number
where a.range_of_value is not null
2、数据库的数据文件属于文件组,每一个数据库有一个主要的文件组,另外可以按需添加文件组。在超大型数据库中要为数据库添加新的文件组,通过把数据划分成几个阵列,使备份管理变的简单,并且潜在的提升了性能。
alter database wc
add filegroup wc_fg6
alter database wc
add file
(
name= wc_fg6_1,
filename = 'd:\wc_fg6_1.ndf'
)
to filegroup wc_fg6
create table dbo.wcT1
(
vid int,
vv varchar(100)
) on [wc_fg6] --指定文件组名
create table dbo.wcT2
(
vid int,
vv varchar(100)
) on [default] --指定是默认文件组
--当表中有text,ntext,image,varchar(max),nvarchar(max),varbinary(max),xml类型的列时,
--可以指定TEXTIMAGE_ON,允许这些数据存储在独立的文件组中
create table dbo.wcT3
(
vid int,
vv varchar(max)
) on [primary] --主文件组primary,这里主文件组也是默认文件组
textimage_on [wc_fg6]
select t.name,
i.name,
ps.name,
dsp.name
from sys.tables t
inner join sys.partitions p
on t.object_id = p.object_id
inner join sys.indexes i
on p.object_id = i.object_id
and p.index_id = i.index_id
inner join sys.data_spaces ds
on ds.data_space_id = i.data_space_id
inner join sys.partition_schemes ps
on ps.data_space_id = ds.data_space_id
inner join sys.destination_data_spaces dds --分区和文件组的对应关系
on dds.partition_scheme_id = ps.data_space_id
and dds.destination_id = p.partition_number --分区号
inner join sys.data_spaces dsp
on dds.data_space_id = dsp.data_space_id --目的地文件组
where p.object_id = object_id('wcT')
数据压缩减少磁盘空间使用
--在创建表时通过with指定压缩选项
create table dbo.wcT4
(
vid int,
vv varchar(100)
) on [default] --指定是默认文件组
with (DATA_COMPRESSION = ROW)
--页压缩包括行压缩、前缀压缩、字典压缩
alter table dbo.wcT4
rebuild with (DATA_COMPRESSION = PAGE)
--不压缩数据
alter table dbo.wcT4
rebuild with (DATA_COMPRESSION = NONE)
--估计数据压缩可以节省的空间
EXEC sys.sp_estimate_data_compression_savings
@schema_name = 'dbo',
@object_name = 'wcT4',
@index_id = NULL,
@partition_number = NULL,
@data_compression = 'ROW'
--指定表的某个分区采用页级压缩
alter table wcT
rebuild partition = 3 with (DATA_COMPRESSION = PAGE)
--在创建分区表时指定各个分区的压缩级别
create table wcT6
(wcId int not null,
wcDate datetime not null)
on wcLeftRangeScheme(wcDate)
with (DATA_COMPRESSION = PAGE ON PARTITIONS (1 TO 2),
DATA_COMPRESSION = ROW ON PARTITIONS (4),
DATA_COMPRESSION = NONE ON PARTITIONS (3)) --分区号必须要加括号
查看分区是否压缩
select data_compression,
data_compression_desc
from sys.partitions
where object_id = 213575799