优化SQLServer--表和索引的分区(二)

简介数据库

    以前一篇简单的介绍了语法和一些基本的概念,隔了一段时间,以为有必要细致的经过实例来总结一下这部份内容。如以前所说,分区就是讲大型的对象(表)分红更小的块来管理,基本单位是行。这也就产生了很大优点, 好比在数据库维护备份还原操做的时候,好比在大量用户访问能致使死锁的时候等等。架构

接下来咱们经过大量实例从分区到展现分区的效果以及一些实际案例来提升对这部分知识的理解。并发

--****************** --1.建立分区函数             --******************app

--Create the partition function: dailyPF            DECLARE @StartDay DATE=DATEADD(dd,-3,CAST(SYSDATETIME() AS DATE));             CREATE PARTITION FUNCTION DailyPF (DATETIME2(0))                 AS RANGE RIGHT FOR VALUES                 (@StartDay, DATEADD(dd,1,@StartDay), DATEADD(dd,2,@StartDay),          DATEADD(dd,3,@StartDay), DATEADD(dd,4,@StartDay) );             GO函数

范围分区函数指定范围的边界,left和right关键字指定当数据库引擎按照剩余从左到右对区间值进行排序是,边界值属于那一边,默认为left。分区范围不能有间隔。工具

--******************            --2. 建立文件组性能

--******************测试

ALTER DATABASE PartitionThis ADD FILEGROUP DailyFG1            GO             ALTER DATABASE PartitionThis ADD FILEGROUP DailyFG2             GO             ALTER DATABASE PartitionThis ADD FILEGROUP DailyFG3             GO             ALTER DATABASE PartitionThis ADD FILEGROUP DailyFG4             GO             ALTER DATABASE PartitionThis ADD FILEGROUP DailyFG5             GO             ALTER DATABASE PartitionThis ADD FILEGROUP DailyFG6             GOspa

这里咱们创建6个文件组,同时也能够为文件组建立文件,对象

建立好的文件和文件组文件

接下来我为文件组建立分区方案:

 

--******************           --3. 建立分区架构            --******************

--           CREATE PARTITION SCHEME DailyPS                 AS PARTITION DailyPF                TO (DailyFG1, DailyFG2, DailyFG3, DailyFG4, DailyFG5, DailyFG6);

 

--******************            --4. 在分区架构上建表            --******************

if OBJECT_ID('OrdersDaily','U') is null            CREATE TABLE OrdersDaily (                OrderDate DATETIME2(0) NOT NULL,                OrderId int IDENTITY NOT NULL,                OrderName nvarchar(256) NOT NULL            ) on DailyPS(OrderDate)            GO

这里咱们将分区函数映射到单个文件组里面,调用咱们以前创建的分区函数便可。而后接着建立表在分区文件上,同时应用分区函数在

OrderDate时间上。这里咱们还须要插入一部分测试数据便于观察,同时建立一个架构便于查询分区

--*******************************           --建立架构            --*******************************

--Create a schema for "partition helper" objects           CREATE SCHEMA [ph] AUTHORIZATION dbo;            GO

--插入测试数据           INSERT OrdersDaily(OrderDate, OrderName)             SELECT DATEADD(ss, t.N, DATEADD(dd,-3,CAST(CAST(SYSDATETIME() AS DATE) AS DATETIME2(0)))) AS OrderDate,                CASE WHEN t.N % 3 = 0 THEN 'Robot' WHEN t.N % 4 = 0 THEN 'Badger'  ELSE 'Pen' END AS OrderName            FROM ph.tally AS t--tally是一个1到10万自增加的表,只有一个字段 N

WHERE N < = 1000;               

INSERT OrdersDaily(OrderDate, OrderName)            SELECT DATEADD(ss, t.N, DATEADD(dd,-2,CAST(CAST(SYSDATETIME() AS DATE) AS DATETIME2(0)))) AS OrderDate,                CASE WHEN t.N % 3 = 0 THEN 'Flying Monkey' WHEN t.N % 4 = 0 THEN 'Junebug'  ELSE 'Pen' END AS OrderName            FROM ph.tally AS t            WHERE N < = 2000;

INSERT OrdersDaily(OrderDate, OrderName)             SELECT DATEADD(ss, t.N, DATEADD(dd,-1,CAST(CAST(SYSDATETIME() AS DATE) AS DATETIME2(0)))) AS OrderDate,                CASE WHEN t.N % 2 = 0 THEN 'Turtle' WHEN t.N % 5 = 0 THEN 'Eraser'  ELSE 'Pen' END AS OrderName            FROM ph.tally AS t            WHERE N < = 3000;

INSERT OrdersDaily(OrderDate, OrderName)             SELECT DATEADD(ss, t.N, CAST(CAST(SYSDATETIME() AS DATE) AS DATETIME2(0))) AS OrderDate,                CASE WHEN t.N % 3 = 0 THEN 'Lasso' WHEN t.N % 2 = 0 THEN 'Cattle Prod'  ELSE 'Pen' END AS OrderName            FROM ph.tally AS t            WHERE N < = 4000;            GO

随即在建立相关的索引

--******************           --7. 建立索引            --******************            --添加汇集索引            ALTER TABLE OrdersDaily            ADD CONSTRAINT PKOrdersDaily                PRIMARY KEY CLUSTERED(OrderDate,OrderId)            GO

--对齐索引            --            CREATE NONCLUSTERED INDEX NCOrderIdOrdersDaily                 ON OrdersDaily(OrderId)            GO

--非对齐索引            CREATE NONCLUSTERED INDEX NCOrderNameOrdersDailyNonAligned                 ON OrdersDaily(OrderName) ON [PRIMARY]            GO

此时创建分区文件数据等条件后,咱们能够看一下相应的文件及数据的状况,能够同过以下DMV来查看

SELECT  SCHEMA_NAME(so.schema_id) AS schema_name ,                   OBJECT_NAME(p.object_id) AS object_name ,                    p.partition_number ,                    p.data_compression_desc ,                    dbps.row_count ,                    dbps.reserved_page_count * 8 / 1024. AS reserved_mb ,                    si.index_id ,                    CASE WHEN si.index_id = 0 THEN '(heap!)'                            ELSE si.name                    END AS index_name ,                    si.is_unique ,                    si.data_space_id ,                    mappedto.name AS mapped_to_name ,                    mappedto.type_desc AS mapped_to_type_desc ,                    partitionds.name AS partition_filegroup ,                    pf.name AS pf_name ,                    pf.type_desc AS pf_type_desc ,                    pf.fanout AS pf_fanout ,                    pf.boundary_value_on_right ,                    ps.name AS partition_scheme_name ,                    rv.value AS range_value            FROM    sys.partitions p            JOIN    sys.objects so                    ON p.object_id = so.object_id                        AND so.is_ms_shipped = 0            LEFT JOIN sys.dm_db_partition_stats AS dbps                    ON p.object_id = dbps.object_id                        AND p.partition_id = dbps.partition_id            JOIN    sys.indexes si                    ON p.object_id = si.object_id                        AND p.index_id = si.index_id            LEFT JOIN sys.data_spaces mappedto                    ON si.data_space_id = mappedto.data_space_id            LEFT JOIN sys.destination_data_spaces dds                    ON si.data_space_id = dds.partition_scheme_id                        AND p.partition_number = dds.destination_id            LEFT JOIN sys.data_spaces partitionds                    ON dds.data_space_id = partitionds.data_space_id            LEFT JOIN sys.partition_schemes AS ps                    ON dds.partition_scheme_id = ps.data_space_id            LEFT JOIN sys.partition_functions AS pf                    ON ps.function_id = pf.function_id            LEFT JOIN sys.partition_range_values AS rv                    ON pf.function_id = rv.function_id                        AND dds.destination_id = CASE pf.boundary_value_on_right                                                    WHEN 0 THEN rv.boundary_id                                                    ELSE rv.boundary_id + 1                                                END

查询结果如图:

分区表

能够发现按照日期的分布产生了不一样文件组的数据插入到了不一样的文件里面和索引里面了。

接下来咱们经过分区切换来更好的理解分区的意义,首先要创建新的文件组(DailyF7)来切换分区,同时建立一个分区表OrdersDailyLoad,并向这个表里面插入5000条数据建立索引等以上的操做单独对此表进行一遍重复操做,来实现对新分区的新标的对齐。注意5000条数据必定要在指定范围内,好比使用check约束使数据在11.30-12.1日内的数据。

 

代码:

在切换以前咱们必定要禁用或者删除掉这个分区的对其的索引   ALTER INDEX NCOrderNameOrdersDailyNonAligned ON OrdersDaily DISABLE;    GO    ALTER TABLE OrdersDailyLoad    SWITCH TO OrdersDaily PARTITION 6;    GO

如图,分区切换后文件组6中变为了5000条数据,而7中变为了空。

image

若是须要切换回来执行

ALTER TABLE PARTITION 6  SWITCH TO OrdersDaily OrdersDailyLoad ;  GO

若是须要合并分区

ALTER PARTITION FUNCTION DailyPF ()           MERGE RANGE (‘2015-11-27 00:00:00.000’)

结果:此界点两个分区将合并为一个

 

 

 

总结:

           经过以上代码和实例的展现,咱们能了解如何使用分区。同时咱们要知道分区的意义。可是要知道分区也是一把双刃剑,它能够看作是一个性能选项、管理选项、可扩展工具,在提升数据查询、维护性能的同时也对数据库的备份还原策略、索引的维护、并发性以及变分区锁等有反作用,因此具体是否选用表分区要根据实际状况来判断,而后推荐一个工具(DataBase Tuning Adcisor)运行工做负载来提供是否分区的建议。

相关文章
相关标签/搜索