Sql Server - 从VLT中删除列(超大表)

Con*_*ger 14 t-sql sql-server

任何人都可以建议最好的实现如下:

要求:从VLT(接近400 gb)中删除5列.

我们尝试这样做的那一刻,我们在PRODUCTION上面临空间问题,超时错误(通过SSMS)

我们试图插入任何临时表(通过保持身份关闭),但随后我们插入了所有近几十亿行数据,我们尝试切换身份,我们面临超时错误.

我们是否应该通过POWERSHELL进行这些操作,与SSMS相比更好

限制:生产空间有限,tempdb因这些操作而快速增长.

请告知,从VLT中删除列的最佳方法是什么.

问候

小智 14

我会采取已经提到的方法之一,但有一些关键的修改.假设您使用的是SQL Server 2008,请执行以下操作:

  1. 使用您想要保留的列创建现有超大型表的零长度副本:

    select top 0 {{column subset}} into tbl_tableB from tableA
    
    Run Code Online (Sandbox Code Playgroud)

    确保还将任何索引,约束等复制到新表.SELECT...INTO语句将适当地处理标识列.

  2. 重命名原始表格; 我们将在下一步中用视图替换它.

    exec sys.sp_rename @objname = 'tableA', @newname = 'tbl_tableA'
    
    Run Code Online (Sandbox Code Playgroud)
  3. 使用原始表名创建视图,并UNION ALL:

    create view tableA
    as
    select {{column subset}} from tbl_tableA
    union all
    select {{column subset}} from tbl_tableB
    
    Run Code Online (Sandbox Code Playgroud)

    这将与查询数据的应用程序保持一定程度的兼容性.INSERTs,, UPDATEsDELETEs将必须通过视图上的触发器来处理.这UNION ALL将防止tempdb中的压力,因为不存在排序(相对于直线UNION),并且我们一次不会存在多于一行的副本.

  4. 使用DELETE组合OUTPUT子句从原始表中批量删除数据,同时将其插入新表中:

    BEGIN TRAN
    DELETE TOP (1000) /* or whatever batch size you want */
    FROM
        tbl_tableA
    OUTPUT (
        DELETED.{{column subset}} /* have to list each column here prefixed by DELETED. */
    )
    INTO
        tbl_tableB (
            {{column subset}} /* again list each column here */
        )
    /* Check for errors */
    /* COMMIT or ROLLBACK */
    /* rinse and repeat [n] times */
    
    Run Code Online (Sandbox Code Playgroud)
  5. 完成DELETEs/后INSERTs,删除视图,删除原始表,重命名新表:

    drop view tableA
    drop table tbl_tableA
    exec sys.sp_rename @objname = 'tbl_tableB', @newname = 'tableA'
    
    Run Code Online (Sandbox Code Playgroud)

这种方法的优点压倒一切的是,DELETEINSERT在同一交易同时发生,这意味着数据将始终保持一致的状态.您可以通过更改TOP子句来增加批处理的大小,从而更好地控制事务日志的使用和阻塞.我已经在有和没有标识列的表上测试了这种精确的方法,它的效果很好.在一张非常大的桌子上,需要一段时间才能运行; 可能是几个小时到几天,但它将完成所需的结果.


Rem*_*anu 11

ALTER TABLE ... DROP本身只是一个元数据操作,只要它能在表上获得一个独占锁,就会几乎瞬间完成,这意味着使用该表的所有查询都必须耗尽(完成).但是删除列并没有实际删除它们,请参阅引擎盖下的SQL Server表列.

如有必要,下一步是删除物理列.如果有必要,我会呼叫,因为根据列类型,它可能不值得努力.对于可变长度列,您可以通过运行来回收空间DBCC CLEANTABLE.但是,如果您在非压缩表上删除了固定大小的列(没有页面或行压缩),那么回收空间的唯一方法是重建表(堆或聚簇索引).如果表已分区,您可以尝试一次重建脱机一个分区(ALTER TABLE ... REBUILD PARTITION = N).如果没有,您的最佳镜头是在线重建,前提是您没有MAX类型列(此限制在SQL Server 2012中解除).在线重建会生成大量日志(至少是数据大小的1.5倍),但它会在内部提交,因此日志备份维护可以回收空间,并且最终不会有600Gb的日志增长.如果在线重建不可行并且表没有分区,那么我将首先重新审视清除drop column的决定.

如果列清理是绝对必须的,并且您没有在线替代方案,那么您真的有一个痛苦的世界.做这么大的操作需要几天的准备,测试,并且完全不是微不足道的.您必须创建具有所需结构的新表,开始批量传输数据并设置一些机制来跟踪对已复制数据所做的更改,然后将这些更改应用于副本.复制所有数据并应用自复制开始后发生的更改,然后您可以使用切换旧表和新表sp_rename.总而言之,你会更好,如果你可以使用现成的现成的在线选项.