我在同一个数据库中有两个具有相同列结构的表:TableA
和TableB
。
TableA
没有任何索引,但TableB
具有非群集唯一索引。
TableA
有2.9亿行需要复制到TableB
的数据。
因为它们都有相同的结构,所以我试过
INSERT INTO TableB
SELECT *
FROM TableA;
它正在执行数小时并生成一个填满磁盘的巨大日志文件。结果,磁盘空间不足,查询被终止。
我可以收缩日志文件。如何有效地将这些行数据复制到另一个表?
答案 0 :(得分:3)
首先,在插入行之前禁用TableB
上的索引。您可以使用T-SQL执行此操作:
ALTER INDEX IX_Index_Name ON dbo.TableB DISABLE;
确保禁用目标表上的所有约束(外键,检查约束,唯一索引)。
加载完成后重新启用(并重建)它们。
现在,有几种解决问题的方法:
INSERT INTO ... SELECT ... FROM ...
语法,但首先将数据库切换到批量记录恢复模式(read before switching )。如果您已经使用Bulk-logged或Simple进行操作,将无济于事。ROWS_PER_BATCH
选项。老派"我不会给出一个该死的"方法:为了防止日志填满,你需要执行 插入成批行,而不是一次插入。如果你的数据库 在完全恢复模式下运行时,您需要保留日志备份 跑步,甚至可能试图增加工作的频率。
要批量加载您的行,您需要WHILE
(不要在其中使用它们)
日常用品,仅用于批量装载),类似于
如果dbo.TableA
中有标识符,则以下内容将起作用
表:
DECLARE @RowsToLoad BIGINT;
DECLARE @RowsPerBatch INT = 5000;
DECLARE @LeftBoundary BIGINT = 0;
DECLARE @RightBoundary BIGINT = @RowsPerBatch;
SELECT @RowsToLoad = MAX(IdentifierColumn) dbo.FROM TableA
WHILE @LeftBoundary < @RowsToLoad
BEGIN
INSERT INTO TableB (Column1, Column2)
SELECT
tA.Column1,
tB.Column2
FROM
dbo.TableA as tA
WHERE
tA.IdentifierColumn > @LeftBoundary
AND tA.IdentifierColumn <= @RightBoundary
SET @LeftBoundary = @LeftBoundary + @RowsPerBatch;
SET @RightBoundary = @RightBoundary + @RowsPerBatch;
END
为了有效地工作,你真的想考虑创建一个
仅在你的时间dbo.TableA (IdentifierColumn)
上的索引
运行负载。