SQL Server分区表 - 如何同步表定义?

时间:2011-11-17 07:14:34

标签: sql-server-2008 partitioning

我们的SQL Server数据仓库广泛使用分区切换,许多表都有用于切换进出各种分区的对等表。

这些“登台”表必须是主表的完美复制品 - 即完全相同的列,相同的约束和相同的索引。

是否有一种智能方法可以使登台表与主表保持同步? 例如你知道任何将主表的DDL语句复制到登台表的DDL触发器,还是保持所有表同步的其他简单方法?

1 个答案:

答案 0 :(得分:1)

我最终编写了以下DDL触发器,它几乎实现了我正在寻找的解决方案:

CREATE TABLE [Helpers].[LoadingTables](
    [SchemaName] [sysname] NOT NULL,
    [TableName] [sysname] NOT NULL,
    [LoadingSchemaName] [sysname] NOT NULL,
    [LoadingTableName] [sysname] NOT NULL,
    [SkipPrimaryKey] [bit] NOT NULL,
    [SkipIndexes] [bit] NOT NULL,
    [SkipConstraints] [bit] NOT NULL,
    [MaintainMergeOnInsertTrigger] [bit] NOT NULL,
    [MaintainArchiveOnDeleteTrigger] [bit] NOT NULL,
 CONSTRAINT [PK_LoadingTables] PRIMARY KEY CLUSTERED 
(
    [SchemaName] ASC,
    [TableName] ASC,
    [LoadingSchemaName] ASC,
    [LoadingTableName] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) 



SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO

IF  EXISTS (SELECT * FROM sys.triggers WHERE parent_class_desc = 'DATABASE' AND name = N'SwitchTableSynchronizer')
BEGIN
    DISABLE TRIGGER [SwitchTableSynchronizer] ON DATABASE;
    DROP TRIGGER [SwitchTableSynchronizer] ON DATABASE;
END 

GO

CREATE TRIGGER [SwitchTableSynchronizer]
ON DATABASE 
FOR DDL_TABLE_EVENTS, DDL_INDEX_EVENTS
AS 
    -- Common properties
    DECLARE @EventType  varchar(100) = EVENTDATA().value('(/EVENT_INSTANCE/EventType)[1]','nvarchar(max)');
    DECLARE @ObjectType varchar(100) = EVENTDATA().value('(/EVENT_INSTANCE/ObjectType)[1]','nvarchar(max)');
    DECLARE @SchemaName varchar(100) = EVENTDATA().value('(/EVENT_INSTANCE/SchemaName)[1]','nvarchar(max)');
    DECLARE @CommandText varchar(max) = EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)');
    DECLARE @TableName varchar(100), 
            @LoadingSchemaName sysname, 
            @LoadingTableName sysname,
            @LoadingFullTableName varchar(max),
            @SkipPrimaryKey bit,
            @SkipIndexes bit,
            @SkipConstraints bit,   
            @MaintainMergeOnInsertTrigger bit,
            @MaintainArchiveOnDeleteTrigger bit,                    
            @SQL varchar(max);

    IF @ObjectType = 'INDEX' 
    BEGIN
        DECLARE @IndexName varchar(100) = EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]','nvarchar(max)');
        SET @TableName = EVENTDATA().value('(/EVENT_INSTANCE/TargetObjectName)[1]','nvarchar(max)');
    END ELSE BEGIN
        SET @TableName  = EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]','nvarchar(max)');
    END

    IF OBJECT_ID('Helpers.LoadingTables') IS NULL RETURN;
    IF NOT EXISTS (SELECT * FROM Helpers.LoadingTables WHERE SchemaName = @SchemaName   AND TableName = @TableName) RETURN;

    DECLARE @FullTableName varchar(max) = '[' + @SchemaName + '].[' + @TableName + ']';

    IF NULLIF(CHARINDEX(@FullTableName, @CommandText), 0) IS NULL
        SET @FullTableName = @SchemaName + '.' + @TableName;

    IF NULLIF(CHARINDEX(@FullTableName, @CommandText), 0) IS NULL
    BEGIN
        DECLARE @msg varchar(max) = @TableName + ' participates in partition switching. Use a schema qualified name when altering this table or int''s indexes.';
        RAISERROR (@msg,18,0);
        IF @@TRANCOUNT > 0 ROLLBACK;
        RETURN;               
    END

    DECLARE LoadersCursor CURSOR FOR 
            SELECT LoadingSchemaName, LoadingTableName, SkipPrimaryKey, SkipIndexes, SkipConstraints, MaintainMergeOnInsertTrigger, MaintainArchiveOnDeleteTrigger
            FROM Helpers.LoadingTables                                                                
            WHERE SchemaName = @SchemaName             
            AND TableName = @TableName;

    OPEN LoadersCursor;
    FETCH NEXT FROM LoadersCursor INTO @LoadingSchemaName, @LoadingTableName, @SkipPrimaryKey, @SkipIndexes, @SkipConstraints,
                                        @MaintainMergeOnInsertTrigger, @MaintainArchiveOnDeleteTrigger;


    WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @LoadingFullTableName = @LoadingSchemaName + '.' + @LoadingTableName
        SET @SQL = REPLACE(@CommandText, @FullTableName, @LoadingFullTableName);

        IF @EventType LIKE 'CREATE_TABLE'
        BEGIN
            SET @SQL = REPLACE(@SQL, @TableName + ' PRIMARY KEY', @LoadingTableName + ' PRIMARY KEY');

            SET @SQL = @SQL + CHAR(13) 
            + 'EXEC sp_addextendedproperty @name = N''microsoft_database_tools_support'', @value = 1, @level0type = ''schema'', @level0name = N''' 
            + @LoadingSchemaName + ''', @level1type = ''table'', @level1name = N''' + @LoadingTableName + ''''; 
        END

        IF @EventType LIKE 'ALTER_TABLE'
        BEGIN
            DECLARE @ConstraintName varchar(max) = EVENTDATA().value('(/EVENT_INSTANCE/AlterTableActionList/*/Constraints/Name)[1]','nvarchar(max)');

            IF @ConstraintName IS NOT NULL
            BEGIN

                DECLARE @NewName varchar(max) = REPLACE(@ConstraintName, @TableName, @LoadingTableName);
                SET @SQL = REPLACE(@SQL, @ConstraintName, @NewName);

                IF @SQL LIKE '%PRIMARY KEY%' AND @SkipPrimaryKey = 1 SET @SQL = NULL;           
                IF @SQL NOT LIKE '%PRIMARY KEY%' AND @SkipConstraints = 1 SET @SQL = NULL;

                IF @SQL LIKE '%REFERENCES ' + @FullTableName + '%'
                BEGIN
                    DECLARE @msg2 varchar(max) = @TableName + ' participates in partition switching and may not participate in self-referencing constraints.';
                    RAISERROR (@msg2,18,0);
                    IF @@TRANCOUNT > 0 ROLLBACK;
                    RETURN;     
                END
            END;
        END

        IF @EventType LIKE '%INDEX' AND @SkipIndexes = 1 SET @SQL = NULL;       

        PRINT @CommandText;
        PRINT @SQL;

        IF @SQL IS NOT NULL AND @SQL <> @CommandText 
        BEGIN
            EXEC (@SQL);
        END 

        FETCH NEXT FROM LoadersCursor INTO @LoadingSchemaName, @LoadingTableName, @SkipPrimaryKey, @SkipIndexes, @SkipConstraints,
                                            @MaintainMergeOnInsertTrigger, @MaintainArchiveOnDeleteTrigger;
    END         

    CLOSE LoadersCursor;
    DEALLOCATE LoadersCursor;
GO