【SQL Server高可用性】分区表、数据库文件组

 

对分区表,特别需要注意的是:

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

 

posted @ 2012-07-17 10:09  小木瓜瓜瓜  阅读(206)  评论(0编辑  收藏  举报