更新包含 120M 记录的表的唯一合理方法是使用填充 second 表的 SELECT 语句。执行此操作时必须小心。说明如下。
简单案例
对于没有聚集索引的表,在没有并发 DML 的时间内:
SELECT *, new_col = 1 INTO clone.BaseTable FROM dbo.BaseTable
- 在新表上重新创建索引、约束等
- 使用 ALTER SCHEMA ... TRANSFER 切换新旧版本。
- 删除旧表
如果您无法创建克隆架构,则可以使用同一架构中的不同表名。请记住在切换后重命名所有约束和触发器(如果适用)。
非简单案例
首先,在不同的架构下重新创建具有相同名称的BaseTable,例如clone.BaseTable。使用单独的架构将简化以后的重命名过程。
-
包括聚集索引(如果适用)。请记住,主键和唯一约束可能是集群的,但不一定如此。
-
包括标识列和计算列(如果适用)。
-
包括您的新 INT 列,无论它属于何处。
-
不包括以下任何内容:
- 触发器
- 外键约束
- 非聚集索引/主键/唯一约束
- 检查约束或默认约束。默认值没有太大区别,但我们正在努力保持
东西最少。
然后,用 1000 行测试您的插入:
-- assuming an IDENTITY column in BaseTable
SET IDENTITY_INSERT clone.BaseTable ON
GO
INSERT clone.BaseTable WITH (TABLOCK) (Col1, Col2, Col3)
SELECT TOP 1000 Col1, Col2, Col3 = -1
FROM dbo.BaseTable
GO
SET IDENTITY_INSERT clone.BaseTable OFF
检查结果。如果一切都按顺序显示:
- 截断克隆表
- 确保数据库采用批量记录或简单恢复模式
- 执行完整插入。
这需要一段时间,但不会像更新那么长。完成后,检查克隆表中的数据,确保一切正确。
然后,重新创建所有非集群主键/唯一约束/索引和外键约束(按此顺序)。如果适用,重新创建默认和检查约束。重新创建所有触发器。在单独的批次中重新创建每个约束、索引或触发器。例如:
ALTER TABLE clone.BaseTable ADD CONSTRAINT UQ_BaseTable UNIQUE (Col2)
GO
-- next constraint/index/trigger definition here
最后,将 dbo.BaseTable 移动到备份架构,将 clone.BaseTable 移动到 dbo 架构(或您的表应该存在的任何位置)。
-- -- perform first true-up operation here, if necessary
-- EXEC clone.BaseTable_TrueUp
-- GO
-- -- create a backup schema, if necessary
-- CREATE SCHEMA backup_20100914
-- GO
BEGIN TRY
BEGIN TRANSACTION
ALTER SCHEMA backup_20100914 TRANSFER dbo.BaseTable
-- -- perform second true-up operation here, if necessary
-- EXEC clone.BaseTable_TrueUp
ALTER SCHEMA dbo TRANSFER clone.BaseTable
COMMIT TRANSACTION
END TRY
BEGIN CATCH
SELECT ERROR_MESSAGE() -- add more info here if necessary
ROLLBACK TRANSACTION
END CATCH
GO
如果您需要释放磁盘空间,此时您可能会删除原始表,但最好将其保留一段时间。
不用说,这是理想的离线操作。如果您在执行此操作时有人在修改数据,则您必须使用模式切换执行校正操作。我建议在dbo.BaseTable 上创建一个触发器,以将所有 DML 记录到单独的表中。在开始插入之前启用此触发器。然后在您执行模式传输的同一事务中,使用日志表执行校正。首先在数据子集上进行测试! Delta 很容易搞砸。