基于日期时间字段的年份标准的分区表

时间:2017-10-22 08:28:26

标签: sql-server ssis

我正在创建一个SSIS包,它执行存储过程并将其结果存储为目标数据库中的表FinancialStatementIds。该表已存在于目标数据库中。我需要对目标表进行分区,并编写了一个脚本来执行此操作。

我提取过去五年的信息并根据年份存储每个分区。所以我创建了5个分区,不包括主分区,分区设置为periodenddate列,这是一个datetime字段。你能否证实它是正确的。我是否需要在分区表中添加任何其他列

我还想知道脚本如何知道它必须对FinancialStatementIds表进行分区

Destinaton表

enter image description here

USE CoreReferenceStaging;  
GO  
-- Adds four new filegroups to the CoreReferenceStaging database  
ALTER DATABASE CoreReferenceStaging  
ADD FILEGROUP CT1;  
GO  
ALTER DATABASE CoreReferenceStaging  
ADD FILEGROUP CT2;  
GO  
ALTER DATABASE CoreReferenceStaging  
ADD FILEGROUP CT3;  
GO  
ALTER DATABASE CoreReferenceStaging  
ADD FILEGROUP CT4;
GO  
ALTER DATABASE CoreReferenceStaging  
ADD FILEGROUP CT5;


-- Adds one file for each filegroup.  
ALTER DATABASE CoreReferenceStaging   
ADD FILE   
(  
    NAME = ctdata1,  
    FILENAME = 'E:\MSSQL10_50.SQL2008R2\MSSQL\DATA\ctdata1.ndf',  
    SIZE = 5MB,  
    MAXSIZE = 100MB,  
    FILEGROWTH = 5MB  
)  
TO FILEGROUP CT1;  
ALTER DATABASE CoreReferenceStaging   
ADD FILE   
(  
    NAME = ctdata2,  
    FILENAME = 'E:\MSSQL10_50.SQL2008R2\MSSQL\DATA\ctdata2.ndf',  
    SIZE = 5MB,  
    MAXSIZE = 100MB,  
    FILEGROWTH = 5MB  
)  
TO FILEGROUP CT2;  
GO  
ALTER DATABASE CoreReferenceStaging   
ADD FILE   
(  
    NAME = ctdata3,  
    FILENAME = 'E:\MSSQL10_50.SQL2008R2\MSSQL\DATA\ctdata3.ndf',  
    SIZE = 5MB,  
    MAXSIZE = 100MB,  
    FILEGROWTH = 5MB  
)  
TO FILEGROUP CT3;  
GO  
ALTER DATABASE CoreReferenceStaging   
ADD FILE   
(  
    NAME = ctdata4,  
    FILENAME = 'E:\MSSQL10_50.SQL2008R2\MSSQL\DATA\ctdata4.ndf',  
    SIZE = 5MB,  
    MAXSIZE = 100MB,  
    FILEGROWTH = 5MB  
)  
TO FILEGROUP CT4;  
GO  
ALTER DATABASE CoreReferenceStaging   
ADD FILE   
(  
    NAME = ctdata5,  
    FILENAME = 'E:\MSSQL10_50.SQL2008R2\MSSQL\DATA\ctdata5.ndf',  
    SIZE = 5MB,  
    MAXSIZE = 100MB,  
    FILEGROWTH = 5MB  
)  
TO FILEGROUP CT5;  
GO  

-- Creates a partition function called financialStatementPartition that will partition a table into four partitions  
CREATE PARTITION FUNCTION financialStatementPartition (datetime)  
    AS RANGE LEFT FOR VALUES (year(getDate()), year(getDate() -1), year(getDate() -2),year(getDate() -4)) ;  
GO  
-- Creates a partition scheme called financialStatementRange that applies financialStatementPartition to the five filegroups created above  
CREATE PARTITION SCHEME financialStatementRange  
    AS PARTITION financialStatementPartition  
    TO (CT1, CT2, CT3, CT4,CT5) ;  
GO  
-- Creates a partitioned table called FinancialStatementPartition that uses financialStatementRange to partition periodenddate  
CREATE TABLE FinancialStatementPartition (periodenddate datetime PRIMARY KEY)  
    ON financialStatementRange (periodenddate) ;  
GO 

表financialstatementIds的DDL

CREATE TABLE [dbo].[FinancialStatementIds](
    [financialCollectionId] [int] NOT NULL,
    [companyId] [int] NOT NULL,
    [dataItemId] [int] NOT NULL,
    [dataItemName] [varchar](200) NULL,
    [dataItemvalue] [decimal](18, 0) NULL,
    [unittypevalue] [int] NULL,
    [fiscalyear] [int] NULL,
    [fiscalquarter] [int] NULL,
    [periodenddate] [datetime] NULL,
    [filingdate] [datetime] NULL,
    [restatementtypename] [varchar](200) NULL,
    [latestforfinancialperiodflag] [bit] NULL,
    [latestfilingforinstanceflag] [bit] NULL,
    [currencyconversionflag] [int] NULL,
    [currencyname] [varchar](200) NULL,
    [periodtypename] [varchar](200) NULL
) ON [PRIMARY]

1 个答案:

答案 0 :(得分:1)

在对具有时间组件的时态类型进行分区时使用RANGE RIGHT。这将确保与分区边界完全匹配的日期放在所需的分区和文件组中。

分区函数边界的日期计算表达式不正确。您应该使用DATEADD而不是从当前日期减去一个整数,这被解释为减去天数。

下面的脚本将创建2013年至2018年(假设2017年运行)年度边界的分区功能和方案,其中包括2018年未来的边界。滑动窗口分区的最佳实践是计划分割空分区以避免分割期间昂贵的数据移动(日志记录大约是DML的4倍),空的未来年分区将确保在分割空分区时不移动任何数据在将数据加载到分区之前。此脚本假定所有文件组和基础文件已存在。

CREATE PARTITION FUNCTION financialStatementPartition (datetime)  
    AS RANGE RIGHT FOR VALUES ();
--the first permanent partition (always empty) 
CREATE PARTITION SCHEME financialStatementRange  
    AS PARTITION financialStatementPartition  
    ALL TO ([PRIMARY]); 
DECLARE @periodenddate datetime = DATEADD(year, -4, DATEADD(year, DATEDIFF(year, '', GETDATE()), ''));
ALTER PARTITION SCHEME financialStatementRange
            NEXT USED CT1;
ALTER PARTITION FUNCTION financialStatementPartition()
            SPLIT RANGE(@periodenddate);
SET @periodenddate = DATEADD(year, 1, @periodenddate);
ALTER PARTITION SCHEME financialStatementRange
            NEXT USED CT2;
ALTER PARTITION FUNCTION financialStatementPartition()
            SPLIT RANGE(@periodenddate);
SET @periodenddate = DATEADD(year, 1, @periodenddate);
ALTER PARTITION SCHEME financialStatementRange
            NEXT USED CT3;
ALTER PARTITION FUNCTION financialStatementPartition()
            SPLIT RANGE(@periodenddate);
SET @periodenddate = DATEADD(year, 1, @periodenddate);
ALTER PARTITION SCHEME financialStatementRange
            NEXT USED CT4;
ALTER PARTITION FUNCTION financialStatementPartition()
            SPLIT RANGE(@periodenddate);
SET @periodenddate = DATEADD(year, 1, @periodenddate);
ALTER PARTITION SCHEME financialStatementRange
            NEXT USED CT5;
ALTER PARTITION FUNCTION financialStatementPartition()
            SPLIT RANGE(@periodenddate);
--create partition for future 2018 year
SET @periodenddate = DATEADD(year, 1, @periodenddate);
ALTER PARTITION SCHEME financialStatementRange
            NEXT USED CT6;
ALTER PARTITION FUNCTION financialStatementPartition()
            SPLIT RANGE(@periodenddate);

我不了解FinancialStatementPartition表的用途或分区的原因。要对dbo.FinancialStatementIds表进行分区,可以创建分区聚簇索引。该表的屏幕截图不包括现有索引,这是执行此任务的重要细节。为了清楚起见,将带有索引和约束的实际CREATE TABLE DDL添加到您的问题中。

请注意,聚簇索引键必须包含分区列作为键的一部分。此外,所有唯一索引(包括主键和唯一约束)必须包含分区列作为键的一部分,以便对齐索引。

下面的示例将通过创建聚簇索引来对堆进行分区。

CREATE CLUSTERED INDEX cdx ON dbo.FinancialStatementIds(datetime) 
            ON financialStatementRange(periodenddate);

要对堆进行分区并保留现有数据,而不是创建分区聚簇索引,请创建一个具有相同模式但名称不同的新分区表表,使用INSERT ... SELECT加载,删除旧表,并重命名具有原始名称的新表。以下是剧本。

CREATE TABLE [dbo].[FinancialStatementIds_Partitioned](
    [financialCollectionId] [int] NOT NULL,
    [companyId] [int] NOT NULL,
    [dataItemId] [int] NOT NULL,
    [dataItemName] [varchar](200) NULL,
    [dataItemvalue] [decimal](18, 0) NULL,
    [unittypevalue] [int] NULL,
    [fiscalyear] [int] NULL,
    [fiscalquarter] [int] NULL,
    [periodenddate] [datetime] NULL,
    [filingdate] [datetime] NULL,
    [restatementtypename] [varchar](200) NULL,
    [latestforfinancialperiodflag] [bit] NULL,
    [latestfilingforinstanceflag] [bit] NULL,
    [currencyconversionflag] [int] NULL,
    [currencyname] [varchar](200) NULL,
    [periodtypename] [varchar](200) NULL
) ON financialStatementRange(periodenddate);
GO 

INSERT INTO dbo.FinancialStatementIds_Partitioned
SELECT *
FROM dbo.FinancialStatementIds WITH(TABLOCKX);
GO
DROP TABLE dbo.FinancialStatementIds;
GO
EXEC sp_rename N'dbo.FinancialStatementIds_Partitioned', N'FinancialStatementIds';
GO

要将这个为期6年的窗口从2013-2018年滑动到2014 - 2019年,请从最早的年度分区中删除数据,并为下一年度创建一个新分区。在SQL Server 2016及更高版本中,可以使用TRUNCATE TABLE...WITH(PARTITIONS...))从特定分区中删除数据。例如:

TRUNCATE TABLE dbo.FinancialStatementIds 
WITH (PARTITIONS($PARTITION.financialStatementPartition('20130101')));

必须在SQL Server 2014及更早版本中切换到此任务的临时表。这是通过创建具有相同模式的对齐登台表来完成的。

CREATE TABLE [dbo].[FinancialStatementIds_Staging](
       [financialCollectionId] [int] NOT NULL,
       [companyId] [int] NOT NULL,
       [dataItemId] [int] NOT NULL,
       [dataItemName] [varchar](200) NULL,
       [dataItemvalue] [decimal](18, 0) NULL,
       [unittypevalue] [int] NULL,
       [fiscalyear] [int] NULL,
       [fiscalquarter] [int] NULL,
       [periodenddate] [datetime] NULL,
       [filingdate] [datetime] NULL,
       [restatementtypename] [varchar](200) NULL,
       [latestforfinancialperiodflag] [bit] NULL,
       [latestfilingforinstanceflag] [bit] NULL,
       [currencyconversionflag] [int] NULL,
       [currencyname] [varchar](200) NULL,
       [periodtypename] [varchar](200) NULL
) ON financialStatementRange(periodenddate);
GO
CREATE INDEX idx ON dbo.FinancialStatementIds_Partitioned_Staging(financialCollectionId);
GO

将最早年份的数据移动到临时表中,然后截断临时表以永久删除年份数据。一旦最旧的年份分区为空,请从函数中删除边界。这会将前两个空分区合并为一个空分区。

ALTER TABLE FinancialStatementIds
SWITCH PARTITION $PARTITION.financialStatementPartition('20130101') 
TO FinancialStatementIds_Staging PARTITION $PARTITION.financialStatementPartition('20130101');

TRUNCATE TABLE FinancialStatementIds_Staging;

ALTER PARTITION FUNCTION financialStatementPartition()
    MERGE RANGE ('20130101');
GO

然后在创建新文件组后为下一年创建分区:

ALTER PARTITION SCHEME financialStatementRange
    NEXT USED CT7;
ALTER PARTITION FUNCTION financialStatementPartition()
    SPLIT RANGE('20190101');

请注意,不需要在不同的文件组上放置分区。虽然在将文件放在单独的存储上时,在专用用例中将分区放在单独的文件组上可能会有一些性能优势,但这不是这种情况。除非您有特定的理由使用多个文件组,否则可以通过将所有分区放在同一文件组中来避免复杂性。