SQL Server 数据分区管理

Posted Do_GH

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL Server 数据分区管理相关的知识,希望对你有一定的参考价值。

SQL Server 支持表和索引分区。 已分区表和已分区索引的数据划分为可以选择分布于一个数据库中多个文件组的单元。 数据是按水平方式分区的,因此多组行映射到单个的分区。 单个索引或表的所有分区都必须位于同一个数据库中。 对数据进行查询或更新时,表或索引将被视为单个逻辑实体。

分区的优点

通过对大型表或索引进行分区,可以具有以下可管理性和性能优点。

  • 可以快速、高效地传输或访问数据的子集,同时又能维护数据收集的完整性。 例如,将数据从 OLTP 加载到 OLAP 系统之类的操作仅需几秒钟即可完成,而如果不对数据进行分区,执行此操作需要几分钟或几小时。

  • 您可以更快地对一个或多个分区执行维护操作。 这些操作的效率更高,因为它们仅针对这些数据子集,而非整个表。 例如,您可以选择在一个或多个分区中压缩数据,或者重新生成索引的一个或多个分区。

  • 您可以根据经常执行的查询类型和硬件配置,提高查询性能。 例如,在分区依据列与表联接的列相同时,查询优化器可以更快地处理两个或多个已分区表之间的相等联接查询。 有关详细信息,请参阅下面的查询。

  • 当 SQL Server 针对 I/O 操作执行数据排序时,它会首先按分区对数据进行排序。 为了提高数据排序性能,可以通过设置 RAID 将多个磁盘中的分区数据文件条带化。 这样一来,尽管 SQL Server 仍按分区对数据进行排序,但它可以同时访问每个分区的所有驱动器。

  • 此外,您可以通过对在分区级别而不是整个表启用锁升级来提高性能。 这可以减少表上的锁争用。 若要通过允许对分区进行锁升级来减少锁争用,请将 ALTER TABLE 语句的 LOCK_ESCALATION 选项设置为“自动”。

分区名词解释

分区函数

一种数据库对象,它定义如何根据某个列(称为分区列)的值将表或索引的行映射到一组分区。 分区列中的每个值都是分区函数的输入,该函数会返回分区值。 分区函数定义表将具有的分区数和分区边界。 例如,如果有一个包含销售订单数据的表,你可能想要基于“日期时间” 列(如销售日期)将表划分为 12 个(按月)分区。

分区方案

将分区函数的分区映射到一组文件组的数据库对象。 在各个文件组上放置分区的主要原因是为了确保可以在分区上独立执行备份操作。 这是因为您可以在各个文件组上执行备份。

分区列

分区函数对表或索引进行分区时所使用的表或索引列。 参与分区函数的计算列必须显式标记为 PERSISTED。 用作索引列时有效的所有数据类型都可以用作分区依据列, timestamp 除外。 无法指定 ntext、 text、 image、 xml、 varchar(max) 、 nvarchar(max) 或 varbinary(max) 数据类型。 此外,无法指定 Microsoft .NET Framework 公共语言运行时 (CLR) 用户定义类型和别名数据类型列。

对齐的索引

与其对应的表建立在同一个分区方案之上的一种索引。 如果表与其索引对齐,SQL Server 则可以快速高效地切换分区,同时又能维护表及其索引的分区结构。 索引要与其基表对齐,并不需要与基表参与相同的命名分区函数。 但是,索引和基表的分区函数实质上必须是相同的,因为:

  1. 分区函数的参数具有相同的数据类型。
  2. 定义了相同数量的分区。
  3. 定义了相同的分区边界值。

创建分区性能考虑

内存使用情况和指导方针

如果正在使用大量分区,我们建议您使用至少 16 GB 的 RAM。 如果系统没有足够的内存,则数据操作语言 (DML) 语句、数据定义语言 (DDL) 语句和其他操作可能会由于内存不足而失败。 如果系统具有 16 GB 的 RAM 并且运行许多大量占用内存的进程,则在运行大量分区的操作时,可能会出现内存不足的情况。 因此,您具有超过 16 GB 的内存越多,您遇到性能和内存问题的可能性就越低。

内存限制可能会影响 SQL Server 生成已分区索引的性能或能力。 如果表中已应用聚集索引,当索引未与其基表或聚集索引对齐时更是如此。 在这种情况下,可能有助于增加 index create memory 服务器配置选项。

创建分区

创建已分区表或索引通常包含四个操作:

  1. 创建将持有分区方案所指定的分区的文件组和相应的文件。
  2. 创建一个分区函数,该函数根据指定列的值将表或索引的各行映射到分区。
  3. 创建一个将已分区表或已分区索引的分区映射到新文件组的分区方案。
  4. 创建或修改表或索引,并指定分区方案作为存储位置。

创建分区文件和文件组

通过ALTER DATABASE语句修改数据库相关信息

ALTER DATABASE database_name
{
    <add_or_modify_files>
  | <add_or_modify_filegroups>
}

<add_or_modify_files>::=
{
    ADD FILE <filespec> [ ,...n ]
        [ TO FILEGROUP { filegroup_name } ]
  | ADD LOG FILE <filespec> [ ,...n ]
  | REMOVE FILE logical_file_name
  | MODIFY FILE <filespec>
}

<filespec>::=
(
    NAME = logical_file_name
    [ , NEWNAME = new_logical_name ]
    [ , FILENAME = {'os_file_name' | 'filestream_path' | 'memory_optimized_data_path' } ]
    [ , SIZE = size [ KB | MB | GB | TB ] ]
    [ , MAXSIZE = { max_size [ KB | MB | GB | TB ] | UNLIMITED } ]
    [ , FILEGROWTH = growth_increment [ KB | MB | GB | TB| % ] ]
    [ , OFFLINE ]
)

<add_or_modify_filegroups>::=
{
    | ADD FILEGROUP filegroup_name
        [ CONTAINS FILESTREAM | CONTAINS MEMORY_OPTIMIZED_DATA ]
    | REMOVE FILEGROUP filegroup_name
    | MODIFY FILEGROUP filegroup_name
        { <filegroup_updatability_option>
        | DEFAULT
        | NAME = new_filegroup_name
        | { AUTOGROW_SINGLE_FILE | AUTOGROW_ALL_FILES }
        }
}
<filegroup_updatability_option>::=
{
    { READONLY | READWRITE }
    | { READ_ONLY | READ_WRITE }
}

【add_or_modify_files】
指定要添加、删除或修改的文件。

语法描述
ADD FILE向数据库中添加文件
TO FILEGROUP { filegroup_name } 指定要将指定文件添加到的文件组。
ADD LOG FILE将要添加的日志文件添加到指定的数据库
REMOVE FILE从 SQL Server 的实例中删除逻辑文件说明并删除物理文件。
logical_file_name 在 SQL Server 中引用文件时所用的逻辑名称
MODIFY FILE指定应修改的文件

【filespec】
控制文件属性

语法描述
NAME指定文件的逻辑名称
NEWNAME指定文件的新逻辑名称
FILENAME指定操作系统(物理)文件名(地址)
SIZE指定文件大小。 SIZE 不适用于 FILESTREAM 文件组
与 ADD FILE 一起指定时,size 是文件的初始大小。 与 MODIFY FILE 一起指定时,size 是文件的新大小,而且必须大于文件的当前大小。默认值为 MB。 指定整数,不包含小数。
MAXSIZE指定文件可增大到的最大文件大小
FILEGROWTH指定文件的自动增量。文件的 FILEGROWTH 设置不能超过 MAXSIZE 设置。

【add_or_modify_filegroups】

语法描述
ADD FILEGROUP向数据库中添加文件组
REMOVE FILEGROUP从数据库中删除文件组。 除非文件组为空,否则无法将其删除。
MODIFY FILEGROUP通过将状态设置为 READ_ONLY 或 READ_WRITE、将文件组设置为数据库的默认文件组或者更改文件组名称来修改文件组。

示例:

-- Adds four new filegroups to the AdventureWorks2012 database  
ALTER DATABASE AdventureWorks2012  
ADD FILEGROUP test1fg;  
GO  
ALTER DATABASE AdventureWorks2012  
ADD FILEGROUP test2fg;  
GO  
ALTER DATABASE AdventureWorks2012  
ADD FILEGROUP test3fg;  
GO  
ALTER DATABASE AdventureWorks2012  
ADD FILEGROUP test4fg;   

-- Adds one file for each filegroup.  
ALTER DATABASE AdventureWorks2012   
ADD FILE   
(  
    NAME = test1dat1,  
    FILENAME = 'C:\\Program Files\\Microsoft SQL Server\\MSSQL13.MSSQLSERVER\\MSSQL\\DATA\\t1dat1.ndf',  
    SIZE = 5MB,  
    MAXSIZE = 100MB,  
    FILEGROWTH = 5MB  
)  
TO FILEGROUP test1fg;  
ALTER DATABASE AdventureWorks2012   
ADD FILE   
(  
    NAME = test2dat2,  
    FILENAME = 'C:\\Program Files\\Microsoft SQL Server\\MSSQL13.MSSQLSERVER\\MSSQL\\DATA\\t2dat2.ndf',  
    SIZE = 5MB,  
    MAXSIZE = 100MB,  
    FILEGROWTH = 5MB  
)  
TO FILEGROUP test2fg;  
GO  
ALTER DATABASE AdventureWorks2012   
ADD FILE   
(  
    NAME = test3dat3,  
    FILENAME = 'C:\\Program Files\\Microsoft SQL Server\\MSSQL13.MSSQLSERVER\\MSSQL\\DATA\\t3dat3.ndf',  
    SIZE = 5MB,  
    MAXSIZE = 100MB,  
    FILEGROWTH = 5MB  
)  
TO FILEGROUP test3fg;  
GO  
ALTER DATABASE AdventureWorks2012   
ADD FILE   
(  
    NAME = test4dat4,  
    FILENAME = 'C:\\Program Files\\Microsoft SQL Server\\MSSQL13.MSSQLSERVER\\MSSQL\\DATA\\t4dat4.ndf',  
    SIZE = 5MB,  
    MAXSIZE = 100MB,  
    FILEGROWTH = 5MB  
)  
TO FILEGROUP test4fg;  
GO  

创建分区函数

CREATE PARTITION FUNCTION partition_function_name ( input_parameter_type )  
AS RANGE [ LEFT | RIGHT ]   
FOR VALUES ( [ boundary_value [ ,...n ] ] )   
[ ; ]

【参数】

语法描述
partition_function_name分区函数名称
input_parameter_type是用于分区的列的数据类型。 所有数据类型都可有效用作分区列,除了 text、 ntext、 image、 xml、 timestamp、 varchar(max)、 nvarchar(max)、 varbinary(max)、别名数据类型或 CLR 用户定义的数据类型。
RANGE [LEFT | RIGHT]指定当间隔值由 数据库引擎 按升序从左到右排序时,boundary_value [ ,…n ] 属于每个边界值间隔的哪一侧(左侧还是右侧)。 如果未指定,则默认值为 LEFT。
boundary_value为已分区表或索引的每个分区指定边界值

若使用LEFT当分界值为1时,1划分给分界值左侧的分区;若使用RIGHT则会划分至分界值右侧的分区

示例:

-- Creates a partition function called myRangePF1 that will partition a table into four partitions  
CREATE PARTITION FUNCTION myRangePF1 (int) AS RANGE LEFT FOR VALUES (1, 100, 1000) ;  
GO  

修改分区函数

修改分区函数只能将一个分区拆为两个分区或将两个分区合并为一个分区。如果想要更改分区的数量,如将10个分区改为5个分区可以使用以下方案:

  1. 创建另一张数据表进行预期的分区操作,再将该表的数据插入另一张表
  2. 将该表还原为堆,再重新创建分区索引
  3. 通过将 Transact-SQL CREATE INDEX 语句与 DROP EXISTING = ON 子句一起使用来删除并重新生成现有的已分区索引。
  4. 执行一系列 ALTER PARTITION FUNCTION 语句。
ALTER PARTITION FUNCTION partition_function_name()  
{   
    SPLIT RANGE ( boundary_value )  
  | MERGE RANGE ( boundary_value )   
} [ ; ]
语法描述
SPLIT RANGE在分区函数中添加一个分区。 boundary_value 确定新分区的范围,因此它必须不同于分区函数的现有边界范围。
MERGE RANGE删除一个分区并将该分区中存在的所有值都合并到某个剩余分区中。 RANGE (boundary_value) 必须是要删除的分区的现有边界值。

示例:

--Split the partition between boundary_values 100 and 1000  
--to create two partitions between boundary_values 100 and 500  
--and between boundary_values 500 and 1000.  
ALTER PARTITION FUNCTION myRangePF1 () SPLIT RANGE (500);  

向分区中插入分界值,SQL Server会自动将数据重新排列放入对应的分区文件中

--Merge the partitions between boundary_values 1 and 100  
--and between boundary_values 100 and 1000 to create one partition  
--between boundary_values 1 and 1000.  
ALTER PARTITION FUNCTION myRangePF1 () MERGE RANGE (100);  

删除分界值,SQL Server会自动将数据重新填充至分区文件中

删除分区函数

DROP PARTITION FUNCTION partition_function_name [ ; ]

创建分区方案

CREATE PARTITION SCHEME partition_scheme_name  
AS PARTITION partition_function_name  
[ ALL ] TO ( { file_group_name | [ PRIMARY ] } [ ,...n ] )  
[ ; ]

【参数】

语法描述
partition_scheme_name分区方案名称
partition_function_name分区方案使用的分区函数名称
all指定所有分区都映射到在 file_group_name 中提供的文件组,或映射到主文件组(如果指定了 [PRIMARY])。 如果指定了 ALL,则只能指定一个 file_group_name。
file_group_name指定用来持有由 partition_function_name 指定的分区的文件组的名称

示例:

-- Creates a partition scheme called myRangePS1 that applies myRangePF1 to the four filegroups created above  
CREATE PARTITION SCHEME myRangePS1  
    AS PARTITION myRangePF1  
    TO (test1fg, test2fg, test3fg, test4fg) ;  
GO  

修改分区方案

ALTER PARTITION SCHEME partition_scheme_name   
NEXT USED [ filegroup_name ] [ ; ]

在一个分区方案中,只能将一个文件组指定为 NEXT USED。 可以指定非空文件组。 如果指定了 filegroup_name 且当前没有文件组被标记为 NEXT USED,则将 filegroup_name 标记为 NEXT USED。 如果指定了 filegroup_name 且已经存在具有 NEXT USED 属性的文件组,则 NEXT USED 属性从现有的文件组转移到 filegroup_name。

删除分区方案

DROP PARTITION SCHEME partition_scheme_name [ ; ]

为数据表创建分区

创建新表时创建分区

CREATE TABLE PartitionTable (col1 int PRIMARY KEY, col2 char(10)) ON myRangePS1 (col1);

使用ON为数据表指定分区方案myRangePS1,同时指定分区列
示例:

-- Creates a partitioned table called PartitionTable that uses myRangePS1 to partition col1  
CREATE TABLE PartitionTable (col1 int PRIMARY KEY, col2 char(10))  
    ON myRangePS1 (col1) ;  
GO

数据表PartitionTable中的数据将根据col1的值被分划到四个分区中,划分内容如下:

分区1234
范围col1 <= 11 < col1 <= 100100 <= col1 < 1000col1 >= 1000

为已存在的数据表创建分区

通过创建索引,为已存在的数据表分区

CREATE CLUSTERED INDEX [CLU_PartitionTable] ON [dbo].[PartitionTable] 
(
	[col1]
)WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [myRangePS1]([col1])

  • 确认数据表是否分区
SELECT *   
FROM sys.tables AS t   
JOIN sys.indexes AS i   
    ON t.[object_id] = i.[object_id]   
    AND i.[type] IN (0,1)   
JOIN sys.partition_schemes ps   
    ON i.data_space_id = ps.data_space_id   
WHERE t.name = 'PartitionTable';   
GO

若该查询能返回结果,则该数据表为分区表


  • 确定已分区表的边界值
SELECT t.name AS TableName, i.name AS IndexName, p.partition_number, p.partition_id, i.data_space_id, f.function_id, f.type_desc, r.boundary_id, r.value AS BoundaryValue   
FROM sys.tables AS t  
JOIN sys.indexes AS i  
    ON t.object_id = i.object_id  
JOIN sys.partitions AS p  
    ON i.object_id = p.object_id AND i.index_id = p.index_id   
JOIN  sys.partition_schemes AS s   
    ON i.data_space_id = s.data_space_id  
JOIN sys.partition_functions AS f   
    ON s.function_id = f.function_id  
LEFT JOIN sys.partition_range_values AS r   
    ON f.function_id = r.function_id and r.boundary_id = p.partition_number  
WHERE t.name = 'PartitionTable' AND i.type <= 1  
ORDER BY p.partition_number;

  • 确定已分区表的分区列
SELECT   
    t.[object_id] AS ObjectID   
    , t.name AS TableName   
    , ic.column_id AS PartitioningColumnID   
    , c.name AS PartitioningColumnName   
FROM sys.tables AS t   
JOIN sys.indexes AS i   
    ON t.[object_id] = i.[object_id]   
    AND i.[type] <= 1 -- clustered index or a heap   
JOIN sys.partition_schemes AS ps   
    ON ps.data_space_id = i.data_space_id   
JOIN sys.index_columns AS ic   
    ON ic.[object_id] = i.[object_id]   
    AND ic.index_id = i.index_id   
    AND ic.partition_ordinal >= 1 -- because 0 = non-partitioning column   
JOIN sys.columns AS c   
    ON t.[object_id] = c.[object_id]   
    AND ic.column_id = c.column_id   
WHERE t.name = 'PartitionTable' ;   
GO

已分区表和已分区索引
创建已分区表和已分区索引
修改分区函数
修改分区方案
ALTER DATABASE (Transact-SQL) 文件和文件组选项
CREATE PARTITION FUNCTION (Transact-SQL)
ALTER PARTITION FUNCTION (Transact-SQL)
DROP PARTITION FUNCTION (Transact-SQL)
CREATE PARTITION SCHEME (Transact-SQL)
ALTER PARTITION SCHEME (Transact-SQL)
DROP PARTITION SCHEME (Transact-SQL)

以上是关于SQL Server 数据分区管理的主要内容,如果未能解决你的问题,请参考以下文章

Sql Server系列:分区表操作

在 SQL Server Management Studio 中从多维数据集中删除分区

MS SQL Server:分区表分区索引 详解

SQL Server 2008如何创建分区表,并压缩数据库空间

sql server 分区

数据库数据恢复SQL Server数据库所在磁盘分区空间不足报错的数据恢复案例