sqlserver 数据库表分区
参考文档 https://msdn.microsoft.com/zh-cn/library/ms345146(SQL.90).aspx
http://blog.sina.com.cn/s/blog_4c8f1ac20100rhu7.html
分区是为了改善大型表以及具有各种访问模式的表的可伸缩性和可管理性。分区使我们不需要将所有数据放到一个位置,但是需要创建和管理许多对象。当所有数据位于一个表中,删除旧数据需要对表及其相关索引进行逐行处理。删除数据的过程将创建大量的日志活动。但是如果使用分区,删除相同数量的数据只需从分区表中删除特定的分区,然后删除或截断独立的表。
SQLServer分区过程:
1、创建文件组
- alter database OrderDB add filegroup [FG_OrderDetail_01];
- alter database OrderDB add filegroup [FG_OrderDetail_02];
2、创建文件组文件
如果有多块硬盘,可以将每个文件组中的文件分配到每个硬盘上,这样可实现分布式磁盘I/O,数据库引擎就可以同时并行检索多块硬盘,提高并发读写速度。
- alter database OrderDB add file(
- name=N'FG_OrderDetail_01'
- ,filename=N'C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\FTData\FG_OrderDetail_01_data.ndf'
- ,size=5MB
- )to filegroup [FG_OrderDetail_01];
- alter database OrderDB add file(
- name=N'FG_OrderDetail_02'
- ,filename=N'C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\FTData\FG_OrderDetail_02_data.ndf'
- ,size=5MB
- )to filegroup [FG_OrderDetail_02];
3、创建分区函数
- create partition function [partition_order_date](datetime)
- as range left for values('20170131 23:59:59.997', '20170228 23:59:59.997')
4、创建分区方案 (若要切换分区需预留一个空分区,该例子以PRIMARY 文件组作为第3个空分区)
- create partition scheme [scheme_order_date] as partition [partition_order_date]
- to ([FG_OrderDetail_01], [FG_OrderDetail_02], [PRIMARY])
5、在分区方案下建表
- CREATE TABLE [dbo].[order_detail](
- [order_id] int NOT NULL,
- [product_id] int NOT NULL,
- [order_qty] int NOT NULL,
- [unit_price] decimal(24,8) NOT NULL,
- [total_amount] decimal(24,8) NOT NULL,
- [order_date] datetime NOT NULL
- CONSTRAINT OrderDetailDateCK CHECK ([order_date] >= '20170101' AND [order_date] < '20170301')
- ) ON [scheme_order_date]([order_date])
6、插入数据
- INSERT dbo.[order_detail](order_id, total_amount, order_date)
- SELECT o.PurchaseOrderID, o.TotalAmount, o.OrderDate
- FROM dbo.PurchaseOrderDetail as o
- WHERE (o.[OrderDate] >= '20170101' AND o.[OrderDate] < '20170301')
7、在分区方案下重建索引
- IF EXISTS(SELECT * FROM sysobjects WHERE name='pk_order_detail' and xtype='PK')
- ALTER TABLE dbo.order_detail DROP CONSTRAINT [pk_order_detail];
- ALTER TABLE dbo.order_detail ADD CONSTRAINT [pk_order_detail]
- PRIMARY KEY CLUSTERED(order_id, product_id) ON [scheme_order_date]([order_date]);
- IF EXISTS (SELECT 1 FROM sysindexes WHERE name = 'idx_order_detail')
- DROP INDEX [idx_order_detail] ON dbo.order_detail;
- CREATE NONCLUSTERED INDEX [idx_order_detail] ON dbo.order_detail(order_date);
8、查看分区情况
(1)查看每个分区的具体数据
- SELECT $partition.partition_order_date(o.order_date) AS [PartitionNo], count(*) AS [RowsInPartition]
- FROM dbo.order_detail AS o
- GROUP BY $partition.partition_order_date(o.order_date)
- ORDER BY [PartitionNo]
(2)查看所有使用分区的表
- Select s.name As SchemaName, t.name As TableName
- From sys.tables t
- Inner Join sys.schemas s On t.schema_id = s.schema_id
- Inner Join sys.partitions p on p.object_id = t.object_id
- Where p.index_id In (0, 1)
- Group By s.name, t.name Having Count(*) > 1 Order By s.name, t.name;
(3)查看分区表的所有分区
- SELECT * FROM sys.partitions WHERE OBJECT_NAME(OBJECT_ID)='order_detail';
上图表示order_details的聚集索引分为3个分区。index_id 0: heap(没有聚集索引的堆表),1:Clustered Index, 2:NonClustered Index
9、分区表连接查询(分区消除,两个表采用同一个分区方案)
表和索引对齐
当多个表使用同一个函数(但不一定使用同一个架构)时,此概念称为对齐。SQL Server 将按类似的方式对具有相同分区键的行进行分组。
具有相同分区键值的相关数据将被放置到同一个文件中,而将必要的数据隔离出来以便进行连接。如果来自多个表的相关行都按照相同的方式进行分区,SQL Server 则可以连接分区,而无需在整个表或多个分区中(如果表使用了不同的分区函数)搜索匹配的行。在这种情况下,不仅可以对齐对象(因为它们使用相同的键),还可以按存储位置对齐(因为相同的数据位于相同的文件中)。
当表和索引按照相同的顺序使用相同的分区函数和列时,表和索引将对齐。使用相同的函数对表及其索引进行分区通常可以优化性能。当表及其索引对齐后,SQL Server 则可以更有效地将分区移入和移出分区表,因为所有相关的数据和索引都使用相同的算法进行划分。
如果定义表和索引时不仅使用了相同的分区函数,还使用了相同的分区架构,则这些表和索引将被认为是按存储位置对齐。按存储位置对齐的一个优点是,相同边界内的所有数据都位于相同的物理磁盘上。在这种情况下,可以单独在某个时间段内执行备份操作,还可以根据数据的变化在备份频率和备份类型方面改变您的策略。如果连接或收集了相同文件或文件组中的表和索引,则可以发现更多的好处。SQL Server 可以通过在多个分区中并行操作来获益。在按存储位置对齐和多 CPU的情况下,每个处理器都可以直接处理特定的文件或文件组,而不会与数据访问产生任何冲突,因为所有需要的数据都位于同一个磁盘上。这样,可以并行运行多个进程,而不会相互干扰。
对存储位置对齐的分区表进行连接查询可以大大提高效率:
- SELECT o.order_id, o.order_date, o.vendor_id, od.product_id, od.order_qty
- FROM dbo.order AS o
- INNER JOIN dbo.order_detail AS od ON o.order_id = od.order_id AND o.order_date = od.order_date
- WHERE o.order_date >= '' AND o.order_date <= '20170131 11:59:59.997'
图二所示,Constant Scan用于获取分区ID, Inner Join将两个分区数据集连接起来。SQL Server 正在消除所有不需要的分区,并且只选择包含正确数据的分区。把光标悬停在“Constant Scan”上会显示Argument参数 VALUES(((1)))),这代表分区号 。
10、删除分区
可参考 https://appliedsql.net/2013/10/08/how-to-remove-a-table-partitioning-in-sql-server/
若表存在聚集索引,可直接去掉聚集索引对分区方案的依赖,否则需要直接删除表
- IF EXISTS(SELECT * FROM sysobjects WHERE name='pk_order_detail' and xtype='PK')
- ALTER TABLE dbo.order_detail DROP CONSTRAINT [pk_order_detail];
- ALTER TABLE dbo.order_detail ADD CONSTRAINT [pk_order_detail] PRIMARY KEY CLUSTERED(order_id, product_id) ON [PRIMARY];
删除分区方案和分区函数
- IF EXISTS (SELECT 1 FROM sys.partition_schemes WHERE name = 'scheme_order_date')
- DROP PARTITION SCHEME scheme_order_date;
- IF EXISTS (SELECT 1 FROM sys.partition_functions WHERE name = 'partition_order_date')
- DROP PARTITION FUNCTION partition_order_date;
删除分区后聚集索引只剩一个分区
滑动窗口方案:
分区表分区切换并没有真正去移动数据,而是 SQL Server 在系统底层改变了表的元数据。因此分区表分区切换是高效、快速、灵活的。利用分区表的分区切换功能,我们可以快速加载数据到分区表。卸载分区数据到普通表,然后 truncate 普通表,以实现快速删除分区表数据。快速归档不活跃数据到历史表。
如果您打算在滑动窗口方案中管理数据,通常需要有一个可以拆分的空分区,以便放置新数据。移入和移出表的过程非常快,而且准备工作可以在分区表外完成。在SQL Server 2005的解决方案中:您可以轻松地移入新填充的分区(作为现有分区架构的额外分区),还可以移出任何旧分区。整个过程只需要很短的时间即可完成,通过使用并行批量加载和并行索引建立,还可以进一步提高效率。更重要的是,因为分区是在表范围之外进行管理的,所以添加分区之前不会对所查询的表造成任何影响。添加一个分区通常只需要几秒钟。当下一个月的数据(在本例中是 2017年03月)可用时,将按特定的操作顺序使用现有的文件组移入和移出数据。
一、管理将要移入的分区的分段表
1. 创建分段表
为了获取更好的性能,将数据加载到未建立索引且未应用约束的堆中,然后在将表移入分区表之前添加约束(参见步骤 3)WITH CHECK。
- CREATE TABLE [dbo].[order_detail_201703](
- [order_id] int NOT NULL,
- [product_id] int NOT NULL,
- [order_qty] int NOT NULL,
- [unit_price] decimal(24,8) NOT NULL,
- [total_amount] decimal(24,8) NOT NULL,
- [order_date] datetime NOT NULL
- ) ON [FG_OrderDetail_01]
2. 加载包含数据的分段表。如果文件是一致的,此过程应该通过 BULK INSERT 语句执行。
如果要将数据单独放到一个新创建的(空)且未建立索引(堆)的表中,则可以先加载数据,而在加载数据之后建立索引。通常情况下,使用这种架构可以获得十倍或更好的性能。实际上,通过加载未建立索引的表可以利用多个 CPU,因此可以并行加载多个数据文件或从同一个文件中加载多个数据块(通过开始和结束行位置来定义)。
3. 加载数据后,即可添加约束。
- ALTER TABLE [dbo].[order_detail_201703]
- WITH CHECK ADD CONSTRAINT OrderDetailDateCK
- CHECK ([order_date] >= '' AND [order_date] <= '20170331 23:59:59.997')
4. 为分段表建立索引。分段表必须与其要移入的表(成为该表的一个分区)具有相同的群集索引。
- ALTER TABLE [dbo].[order_detail_201703]
- ADD CONSTRAINT pk_order_detail PRIMARY KEY CLUSTERED (order_id, product_id) ON [FG_OrderDetail_01]
二、创建将要移出的分区的分段表
1. 创建第二个分段表。这是一个空表,用于存储移出的分区中的数据
- CREATE TABLE [dbo].[order_detail_201701](
- [order_id] int NOT NULL,
- [product_id] int NOT NULL,
- [order_qty] int NOT NULL,
- [unit_price] decimal(24,8) NOT NULL,
- [total_amount] decimal(24,8) NOT NULL,
- [order_date] datetime NOT NULL
- ) ON [FG_OrderDetail_01]
2. 为分段表建立索引。分段表必须与其要移入的表(成为该表的一个分区,而该分区将成为此表)具有相同的群集索引。
- ALTER TABLE [dbo].[order_detail_201701]
- ADD CONSTRAINT pk_order_detail PRIMARY KEY CLUSTERED (order_id, product_id) ON [FG_OrderDetail_01]
三、移出旧数据,并将新数据移入分区表。
1. 移出旧数据,放入第二个分段表中。
- ALTER TABLE [dbo].[order_detail] SWITCH PARTITION 1 TO [dbo].[order_detail_201701]
2. 更改分区函数以删除2017年1月的边界点。此操作还会删除文件组与分区架构之间的关联。具体来说,FG_OrderDetail_01将不再是分区架构的一部分。
- ALTER PARTITION FUNCTION Fun_OrderDetail() MERGE RANGE ('20170131 23:59:59.997')
3. 滚动现有2个分区的新数据,使FG_OrderDetail_01成为“下一个使用的”分区,此分区将是下一个用于拆分的分区。
- ALTER PARTITION SCHEME Sch_OrderDetail NEXT USED [FG_OrderDetail_01]
4. 更改分区函数,为2017年3月添加新的边界点。
- ALTER PARTITION FUNCTION Fun_OrderDetail() SPLIT RANGE ('20170331 23:59:59.997')
5. 更改基础表的约束定义(如果存在),以允许新范围的数据。
因为添加约束的代价可能很昂贵(需要验证数据),所以最好的做法是继续扩大日期范围,而不是删除并重新创建约束。现在,只存在一个约束(OrderDetailDateCK),但以后将存在两个约束。
- ALTER TABLE [dbo].[order_detail] ADD CONSTRAINT OrderDetailMinDateCK CHECK ([order_date] >= '')
- ALTER TABLE [dbo].[order_detail] ADD CONSTRAINT OrderDetailMaxDateCK CHECK ([order_date] < '')
- ALTER TABLE [dbo].[order_detail] DROP CONSTRAINT OrderDetailDateCK
6. 从第一个分段表中移入新数据。
- ALTER TABLE [dbo].[order_detail_201703] SWITCH TO [dbo].[order_detail] PARTITION 2
四、删除分段表
- DROP TABLE [dbo].[order_detail_201701]
- DROP TABLE [dbo].[order_detail_201703]
五、备份文件组
最后一步备份的对象是根据您的备份策略选择的。如果选择了基于文件或文件组的备份策略,则应执行文件或文件组备份。如果选择了基于整个数据库的备份策略,则可以执行完整数据库备份或差异备份。
- BACKUP DATABASE OrderDB FILEGROUP = 'FG_OrderDetail_01' TO DISK = 'C:\OrderDB\OrderDB.bak'
总结
SQL Server 允许根据范围进行分区,还允许将表和索引都设计为使用相同的架构,以便更好地对齐。SQL Server 2005 已经考虑了如何简化分区的管理、开发和使用。它在性能和可管理性方面有以下优点:
简化了需要进行分区以改善性能或可管理性的大型表的设计和实现。
将数据加载到现有分区表的新分区中时,最大程度地减少了对其他分区中的数据访问的影响。
将数据加载到现有分区表的新分区中时,性能相当于将同样的数据加载到新的空表中。
在存档和/或删除分区表的一个分区时,最大程度地减少了对表中其他分区的访问的影响。
允许通过将分区移入和移出分区表来维护分区。
提供了更好的伸缩性和并行性,可以对多个相关表执行大量操作。
改善了所有分区的性能。
缩短了查询优化时间,因为不需要单独优化每个分区。
附加:合理组织数据库文件和文件
sqlserver 数据库表分区的更多相关文章
- 千万级SQL Server数据库表分区的实现
千万级SQL Server数据库表分区的实现 2010-09-10 13:37 佚名 数据库 字号:T | T 一般在千万级的数据压力下,分区是一种比较好的提升性能方法.本文将介绍SQL Server ...
- SQLSERVER数据库表各种同步技术
1 --SQLSERVER数据库表各种同步技术 减少SQLServer中每次的同步数据量 2 3 --说到数据库,我就不由地想到同步数据,如何尽可能地减少每次的同步数据量,以此来提高同步效率,降低对网 ...
- Oracle数据库表分区
一.Oracle数据库表分区概念和理解 1.1.已经存在的表没有方法可以直接转化为分区表. 1.2.不在分区字段上建立分区索引,在别的字段上建立索引相当于全局索引.效率 ...
- zabbix(4)数据库表分区优化
一.zabbix 数据库存储 zabbix-server将采集到的数据存储在数据库(mysql.oracle等),而数据存储的大小与每秒处理的数量量有关,因此数据存储取决于以下两个因数: (1)Req ...
- SqlServer数据库表生成C# Model实体类SQL语句——补充
在sql语句最前边加上 use[数据库名] 原链接:https://www.cnblogs.com/jhli/p/11552105.html --[SQL骚操作]SqlServer数据库表生成C ...
- MySQL数据库表分区功能详解
1.什么是表分区? mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面(可以通过my.cnf中的datadir来查看),一张表主要对应着三个文件,一个是frm存放表 ...
- mysql数据库表分区详解(数量过大的数据库表通过分区提高查询速度)
这篇文章主要介绍了MySQL的表分区,例如什么是表分区.为什么要对表进行分区.表分区的4种类型详解等,需要的朋友可以参考下 一.什么是表分区通俗地讲表分区是将一大表,根据条件分割成若干个小表.mysq ...
- SqlServer数据库表导入SqlLite数据库表保持日期时间类型字段的格式
在写查询功能的过程中遇到一个这样的问题:按日期范围查询,sql语句是:where dt>=用户选择起始日期&&dt<=用户选择结束日期.数据库中的数据如图1,我选择的测试数 ...
- Zabbix数据库表分区
zabbix的监控主机数量将近300,且运行了一年时间了,最近zabbix server服务监控历史数据等服务不断自身告警.查询性能也变得很低 关于历史数据的两个参数,在zabbix server的配 ...
随机推荐
- 读书笔记<深入理解JVM>01 关于OutOfMemoryError 堆空间的溢出
代码片段如下: package com.gosaint.shiro; import java.util.ArrayList; import java.util.List; public class H ...
- 无人驾驶——4.控制之MPC模型预测控制
源自:<无人驾驶无人驾驶车辆模型预测控制>——龚建伟 参考:https://wenku.baidu.com/view/8e4633d519e8b8f67c1cb9fa.html 0.车辆模 ...
- R: plot 绘图各种参数,以及 legend。。
################################################### 问题:基础绘图plot 18.4.30 plot函数,基础绘图的各个参数? 解决方案: ca ...
- 红帽企业版RHEL7.1在研域工控板上,开机没有登陆窗口 -- 编写xorg.conf 简单三行解决Ubuntu分辩率不可调的问题
红帽企业版RHEL7.1在研域工控板上,开机没有登陆窗口 没有登陆窗口 的原因分析: 没有登陆窗口的原因是因为有多个屏幕在工作,其中一个就是build-in 屏幕(内置的虚拟屏幕)和外接的显示器,并且 ...
- Shell表达式,如${file##*/}
Shell表达式,如${file##*/} 2017年10月26日 15:24:40 阅读数:343 今天看一个脚本文件的时候有一些地方不太懂,找了一篇文章看了一些,觉得不错,保留下来. 假设我们定义 ...
- Bulma 源码解析之 .columns 类
{说明} 这一部分的源码内容被我简化了,另外我还额外添加了一个辅助类 is-grow. .columns // 修饰类 &.is-centered justify-content: cente ...
- 利用using和try/finally语句来清理资源
使用非托管资源的类型必须实现IDisposable接口的Dispose()方法来精确的释放系统资源..Net环境的这一规则使得释放资源代码的职责 是类型的使用者,而不是类型或系统.因此,任何时候你在使 ...
- Mac下的UI自动化测试 (一)
在我看来,实现UI自动化测试的过程一向都是令人快乐的事情,而维护它们就是跟噩梦一样了,尤其是对每次CI产生的build进行BVT测试,由于开发不会告诉你任何UI的变化,那么你拿到的测试结果就势必会一片 ...
- 利用python传送文件
转:微信公众号李云景(侵删) 很多人传送文件都是使用QQ,微信,百度云,或者其他网盘. 不过都有微信的传输文件有大小的限制,百度云就不说了,想要正常的下载速度反而要充VIP. 我一直推崇大家都学习Py ...
- kolla出现问题时的定位方式
前提,对官网问题的一个翻译 Troubleshooting Guide排障手册 1.Failures(失败) If Kolla fails, often it is caused by a CTRL- ...