Sql server 如何将大量数据从一个表复制到同一数据库中的另一个表?

Sql server 如何将大量数据从一个表复制到同一数据库中的另一个表?,sql-server,sql-server-2014,Sql Server,Sql Server 2014,我在同一数据库中有两个具有相同列结构的表:TableA和TableB TableA没有任何索引,但TableB有一个非聚集唯一索引 TableA有2.9亿行数据需要复制到TableB 因为它们都有相同的结构,我试过了 INSERT INTO TableB SELECT * FROM TableA; 它执行了数小时,产生了一个巨大的日志文件,填满了磁盘。因此,磁盘空间不足,查询被终止 我可以缩小日志文件。如何有效地将这些多行数据复制到另一个表中?首先,在插入行之前禁用表B上的

我在同一数据库中有两个具有相同列结构的表:
TableA
TableB

TableA
没有任何索引,但
TableB
有一个非聚集唯一索引

TableA
有2.9亿行数据需要复制到
TableB

因为它们都有相同的结构,我试过了

INSERT INTO TableB 
    SELECT * 
    FROM TableA;
它执行了数小时,产生了一个巨大的日志文件,填满了磁盘。因此,磁盘空间不足,查询被终止


我可以缩小日志文件。如何有效地将这些多行数据复制到另一个表中?

首先,在插入行之前禁用
表B上的索引。您可以使用T-SQL执行此操作:

ALTER INDEX IX_Index_Name ON dbo.TableB DISABLE;  
确保禁用目标表上的所有约束(外键、检查约束、唯一索引)

加载完成后重新启用(并重建)它们

现在,有两种方法可以解决这个问题:

  • 您必须对数据丢失的轻微可能性保持正常。:使用
    插入到。。。选择。。。从…
    语法,您必须先将数据库切换到大容量日志恢复模式()。如果您已经进行了批量日志记录或简单日志记录,则不会有帮助
  • 先导出数据:您可以使用BCP实用程序导出/导入数据。它支持批量加载数据。了解有关使用BCP实用程序的更多信息
  • Fancy,首先导出数据:使用SQL 2012+可以尝试将数据导出到二进制文件(使用BCP实用程序)中,并使用语句加载数据,设置
    每批行数
    选项
  • 老派的“我一点也不在乎”方法:为了防止日志被填满,您需要执行 成批插入行,而不是一次插入所有内容。如果你的数据库 正在以完全恢复模式运行,您需要保留日志备份 运行,甚至可能尝试增加作业的频率

    要批量加载行,您需要一个
    ,而
    (不要在中使用它们)
    日常用品,仅用于批量装载),类似
    如果您在
    dbo.TableA
    表:

    声明@RowsToLoad BIGINT;
    声明@RowsPerBatch INT=5000;
    声明@LeftBoundary BIGINT=0;
    声明@rightbundary BIGINT=@RowsPerBatch;
    从表A中选择@RowsToLoad=MAX(IdentifierColumn)dbo
    而@LeftBoundary<@RowsToLoad
    开始
    插入表B(第1列、第2列)
    挑选
    tA.1,
    tB.2
    从…起
    dbo.TableA作为tA
    哪里
    tA.IdentifierColumn>@LeftBoundary
    
    还有tA.IdentifierColumn看看这个也许会对你有所帮助。要复制2.9亿行,您需要将其分解为块。不确定每行中有多少数据,但在单个语句中执行此操作时,它必须记录所有数据,以便在出现错误时回滚。将其分块或使用BulkInsert将减轻日志的压力,因为每个事务不需要太多数据。是否有主键列,如果是,它是什么数据类型?
    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