分区管理

对表分区,对数据库有很多好处,通常来说,分区的好处有两个:减少产生死锁的竞争条件,和删除分区的数据。由于分区之间是相互独立的,因此,对一个分区加X锁,不会对其他分区产生竞争,这是避免死锁(dead lock)的一种方式。对大数据表进行数据删除操作时,可以使用分区切换,使用少量的IO,从分区表中删除海量的数据。

在实际的项目中,有如下的分区函数和分区架构( Partition Scheme):

CREATE PARTITION FUNCTION [funcPartition_int_DataSourceID](int) 
AS RANGE LEFT 
FOR VALUES (1, 2, 3)

CREATE PARTITION SCHEME [schePartition_int_DataSourceID] 
AS PARTITION [funcPartition_DataSourceID] 
TO ([PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY])


create table dbo.dt_test
(
...More column definition

DataSourceID int
)
on [schePartition_int_DataSourceID](DataSourceID)
View Code

一,减少产生死锁的竞争条件

查看ETL的执行日志,日志中记录Package执行的消息,某些Package会因为发送死锁,作为死锁牺牲品(victim)而失败。查看这些Package,发现产生死锁的根本原因是:不同的Package同时更新同一张表,导致竞争,产生死循环而发生死锁。深入分析发生死锁的TSQL脚本,两个Package都使用 DataSourceID 作为过滤条件。推测,可能的原因是这两个DataSourceID位于同一个分区:

1,验证边界值

分区函数设置的边界值是执行分区的依据,验证边界值,能够确定分区列是否处于相同的分区中:

select prv.function_id,pf.name,pf.boundary_value_on_right,prv.value as BoundaryValue
from sys.partition_range_values prv
inner join sys.partition_functions pf
    on prv.function_id=pf.function_id
where pf.name='funcPartition_int_DataSourceID'

边界值小于当前 DataSourceID的最大值,因此,产生竞争的两个DataSourceID 都是在最右边的分区中。缺少分区的管理计划,这会导致额外增加的分区列(DataSourceID)都被分配到同一个分区中。

2,管理分区计划

对表表去,不仅要有效地避免死锁,减少产生死锁的竞争条件,还要在删除大表数据时,使用少量IO实现海量数据的移动,通过分区切换(switch)和数据表截断(truncate),快速删除数据。分区切换是把整个分区切换到零时表中,这就要求,该分区列必须足够小,能够全部删除。管理分区计划的最佳实践,合理选择分区列,并预留空分区。

如果一个分区是非空的,那么分区拆分(split range)会导致数据的移动,这可能是一个非常耗费IO的一个操作,为了避免密集的数据移动,最好是预留一个空的分区,一般是最右边的分区,该分区号最大,每次都把最右边的分区拆分成两个分区:

declare @CurrentMaxBoundaryValue int
declare @ExistingMaxDataSourceID int
declare @BoudaryValue int
declare @sql_prefix nvarchar(max)
declare @sql nvarchar(max)

set @sql_prefix=N'
alter partition scheme [schePartition_int_DataSourceID]
next used [primary]
alter partition function [funcPartition_int_DataSourceID]()
split range ('

select @ExistingMaxDataSourceID = max(ds.DataSourceID)
from dbo.dt_DataSource ds with(nolock)

select @CurrentMaxBoundaryValue= max(cast(prv.value as int))
from sys.partition_functions pf 
inner join sys.partition_range_values prv
    on pf.function_id=prv.function_id
where pf.name='funcPartition_int_DataSourceID'

-- add new boundary value
if @CurrentMaxBoundaryValue<@ExistingMaxDataSourceID+1
begin
    set @BoudaryValue=@CurrentMaxBoundaryValue+1

    while @BoudaryValue<=@ExistingMaxDataSourceID+1
    begin   
        select @sql = @sql_prefix+ cast(@BoudaryValue as varchar(10))+ N')'
        exec(@sql)

        set @BoudaryValue=@BoudaryValue+1
    end
end
View Code

二,可能出现的错误

1,SET选项错误

在执行分区脚本对索引进行分区的,可能会遇到SET选项错误,根据错误消息,启用想用的SET选项:

UNKNOWN TOKEN failed because the following SET options have incorrect settings: 'QUOTED_IDENTIFIER'. Verify that SET options are correct for use with indexed views and/or indexes on computed columns and/or filtered indexes and/or query notifications and/or XML data type methods and/or spatial index operations. [SQLSTATE 42000] (Error 1934).  

上述消息表面当前数据库的QUOTED_IDENTIFIER设置错误,使用SET命令启用QUOTED_IDENTIFIER选项:

SET QUOTED_IDENTIFIER  ON

 

 

 

参考文档:

SET QUOTED_IDENTIFIER (Transact-SQL)

posted @ 2015-12-23 16:41  悦光阴  阅读(678)  评论(0编辑  收藏  举报