Bal*_*ala 3 sql-server sql-server-2014
我在同一个数据库中有两个具有相同列结构的表:TableA和TableB.
TableA没有任何索引,但TableB有一个非聚集唯一索引。
TableA有 2.9 亿行数据需要复制到TableB.
由于它们都具有相同的结构,我已经尝试过
INSERT INTO TableB
SELECT *
FROM TableA;
Run Code Online (Sandbox Code Playgroud)
它执行了几个小时,并产生了一个巨大的日志文件,填满了磁盘。结果磁盘空间不足,查询被终止。
我可以缩小日志文件。如何有效地将这些多行数据复制到另一个表?
首先,TableB在插入行之前禁用索引。您可以使用 T-SQL 来做到这一点:
ALTER INDEX IX_Index_Name ON dbo.TableB DISABLE;
Run Code Online (Sandbox Code Playgroud)
确保禁用目标表上的所有约束(外键、检查约束、唯一索引)。
加载完成后重新启用(并重建)它们。
现在,有几种方法可以解决这个问题:
INSERT INTO ... SELECT ... FROM ...您拥有的语法,但首先将数据库切换到大容量日志恢复模式(切换前阅读)。如果您已经处于 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
Run Code Online (Sandbox Code Playgroud)
为了使其有效地工作,您真的要考虑dbo.TableA (IdentifierColumn)在运行负载时为其创建索引。
| 归档时间: |
|
| 查看次数: |
3311 次 |
| 最近记录: |