SQL Server按月分区使用持久化列,同时创建聚集列存储索引

问题描述

我在 sql Server 中创建了一个分区表,如下所示:

--Add File Groups
ALTER DATABASE TEST ADD FILEGROUP JAN;
GO
ALTER DATABASE TEST ADD FILEGROUP FEB;
GO
ALTER DATABASE TEST ADD FILEGROUP MAR;
GO
... to DEC

--create files 
ALTER DATABASE [Test] 
ADD FILE (NAME = N'JAN',FILENAME = N'C:\Program Files\Microsoft sql Server\MSsql13.MSsqlSERVER\MSsql\DATA\Part_JAN.ndf',SIZE = 5120KB,FILEGROWTH = 1024KB ) TO Filegroup [JAN]

ALTER DATABASE [Test] 
ADD FILE ( NAME = N'FEB',FILENAME = N'C:\Program Files\Microsoft sql Server\MSsql13.MSsqlSERVER\MSsql\DATA\Part_FEB.ndf',FILEGROWTH = 1024KB ) TO Filegroup [FEB]

ALTER DATABASE [Test] 
ADD FILE ( NAME = N'MAR',FILENAME = N'C:\Program Files\Microsoft sql Server\MSsql13.MSsqlSERVER\MSsql\DATA\Part_MAR.ndf',FILEGROWTH = 1024KB ) TO Filegroup [MAR]
... to DEC

--Create Partition Function & Partition Schema
DROP PARTITION FUNCTION partition_ByMonth

CREATE PARTITION FUNCTION partition_ByMonth (int) 
    AS RANGE RIGHT FOR VALUES (2,3,4,5,6,7,8,9,10,11,12) ;
GO

-- Creates a partition scheme called myRangePS1 that applies myRangePF1 to the four filegroups created above
CREATE PARTITION SCHEME Partition_Schema_ByMonth
    AS PARTITION partition_ByMonth
    TO (JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC) ;
GO

--Create Table
CREATE TABLE [TEST].[TEST_PS_MONTH]
(
    [ID] [varchar](4) not null,[VALUE] [varchar](30) null,[ETL_Date] [datetime] not null,[ETL_Month] as MONTH([ETL_Date]) PERSISTED,CONSTRAINT(AK_TEST_PS_MONTH) UNIQUE NONCLUSTERED
    ([ID] ASC,[ETL_Month] ASC)
               WITH (PAD_INDEX= OFF) ON Partition_Schema_ByMonth([ETL_Month])
) ON Partition_Schema_ByMonth([ETL_Month])
GO

然后我想创建聚集列存储索引

---- create clustered column store index (col compression)
CREATE CLUSTERED COLUMNSTORE INDEX [IDX_TEST_PS_MONTH]
ON TEST.TEST_PS_MONTH
WITH (DROP_EXISTING = OFF,COMPRESSION_DELAY = 0) ON Partition_Schema_ByMonth([ETL_Month])
GO

但我收到以下错误

消息 35307,级别 16,状态 1,第 177 行
该语句失败,因为表 'TEST_PS_MONTH' 上的列 'ETL_Month' 是计算列。列存储索引不能隐式或显式包含计算列。

有没有办法压缩按计算月份分区的表?

谢谢!

解决方法

由于您的目标是基于 ETL_Date 月保持 12 个月的滑动窗口,因此您可以直接在 ETL_Date 上进行分区,而无需计算列。创建具有初始每月日期边界的分区函数。然后运行每月维护以截断最旧的月份数据,删除旧边界,并为下个月创建新边界。我建议您使用单个文件组,除非您有其他需要。

以下是此策略的初始设置示例,期限为 13 个月(2020-01-01 至 2020-01-01)。

CREATE PARTITION FUNCTION partition_ByMonth_Function (datetime) 
    AS RANGE RIGHT FOR VALUES();
CREATE PARTITION SCHEME partition_ByMonth_Scheme
    AS PARTITION partition_ByMonth_Function
    ALL TO ([PRIMARY]);
GO
DECLARE 
     @PartitionDate datetime = '20200101',@EndDate datetime = '20210101';
WHILE @PartitionDate <= @EndDate
BEGIN
    ALTER PARTITION SCHEME partition_ByMonth_Scheme NEXT USED [PRIMARY];
    ALTER PARTITION FUNCTION partition_ByMonth_Function() SPLIT RANGE(@PartitionDate);
    SET @PartitionDate = DATEADD(month,1,@PartitionDate);
END;
GO
CREATE TABLE [TEST].[TEST_PS_MONTH]
(
    [ID] [varchar](4) not null,[VALUE] [varchar](30) null,[ETL_Date] [datetime] not null,CONSTRAINT AK_TEST_PS_MONTH UNIQUE NONCLUSTERED
        ([ID] ASC,[ETL_Date] ASC)
        WITH (PAD_INDEX= OFF) ON partition_ByMonth_Scheme([ETL_Date])
) ON partition_ByMonth_Scheme([ETL_Date]);
GO
CREATE CLUSTERED COLUMNSTORE INDEX [IDX_TEST_PS_MONTH]
ON TEST.TEST_PS_MONTH
WITH (DROP_EXISTING = OFF,COMPRESSION_DELAY = 0) ON partition_ByMonth_Scheme([ETL_Date])
GO

每月维护脚本示例(删除最旧的 2020-01-01 月份并添加新的 2021-02-01 月份):

DECLARE 
      @OldestPartitionDate datetime = '20200101',@NewPartitionDate datetime = '20210201';
BEGIN
    TRUNCATE TABLE [TEST].[TEST_PS_MONTH] WITH(PARTITIONS ( $PARTITION.partition_ByMonth_Function(@OldestPartitionDate) ) );
    ALTER PARTITION FUNCTION partition_ByMonth_Function() MERGE RANGE(@OldestPartitionDate);
    ALTER PARTITION SCHEME partition_ByMonth_Scheme NEXT USED [PRIMARY];
    ALTER PARTITION FUNCTION partition_ByMonth_Function() SPLIT RANGE(@NewPartitionDate);
END;
GO