【问题标题】:Bulk Insert from table to table从表到表的批量插入
【发布时间】:2012-06-21 11:16:52
【问题描述】:

我正在实现 A/B/View 场景,这意味着 View 指向 table A,而 table B 更新,然后发生切换,并且在加载表 A 时视图指向表 B。

切换每天发生。有数百万行要更新,成千上万的用户正在查看视图。我在 SQL Server 2012 上。

我的问题是:

  • 如何以最快的方式将数据从另一个表插入到一个表中? (在存储过程中)
  • 有什么方法可以使用 BULK INSERT?或者,使用常规插入/选择是最快的方式吗?

【问题讨论】:

    标签: sql sql-server insert bulkinsert


    【解决方案1】:

    您可以从 SrcTable 中将一个 Select ColA、ColB 放入 DestTable_New。加载 DestTable_New 后,重新创建索引和约束。

    然后将 DestTable 重命名为 DestTable_Old 并将 DestTable_New 重命名为 DestTable。重命名非常快。如果结果出现问题,您还可以备份附近的前一个表 (DestTable_Old)。

    我曾经做过这种场景,我们必须让系统 24/7 全天候运行,并且每天需要加载数千万行。

    【讨论】:

      【解决方案2】:

      我倾向于使用 SSIS。

      将表 A 设为 OLEDB 源,将表 B 设为 OLEDB 目标。您将绕过事务日志,从而减少数据库的负载。使用 T-SQL 执行此操作的唯一方法(我能想到的)是更改整个数据库的恢复模型,这远非理想,因为这意味着不存储任何事务,而不仅仅是用于传输的事务。

      设置 SSIS 传输

      创建一个新项目并将数据流任务拖到您的设计界面

      双击您的数据流任务,这将带您进入“数据流”选项卡。然后从“数据流源”菜单中拖放一个 OLE DB 源,从“数据流目标”菜单中拖放一个 OLE DB 目标

      双击 OLE DB 源,设置与服务器的连接,选择要从中加载的表,然后单击确定。将绿色箭头从 OLE DB 源拖动到目标,然后双击目标。设置您的连接管理器、目标表名称和列映射,您应该一切顺利。

      OLE DB Source docs on MSDN

      OLE DB Destination docs on MSDN

      【讨论】:

      • 是的,事务日志是一个问题。您是否有任何关于如何将源表设置为 OLEDB 源的示例?网上的例子都是关于从文本文件中加载的……谢谢。
      【解决方案3】:

      你可以这样做

      SELECT fieldnames
      INTO DestinationTable
      FROM SourceTable
      

      正如几个答案所建议的那样,这应该尽可能快(取决于您需要重新创建多少索引等)。

      但我建议使用 synonyms 将指针从一个表更改为另一个表。它们非常透明,在我看来,比更新视图或重命名表更干净。

      【讨论】:

      • 对于直接SELECT * 类型的功能,同义词会更有效。它们对于跨数据库引用也非常有用。
      • 实际上,我可能不得不坚持使用视图,因为视图提供了需要删除和重新创建同义词的 ALTER 功能。
      • 此方法不是批量插入,会产生大量日志
      【解决方案4】:

      我知道这个问题很老,但我一直在寻找同一个问题的答案,但没有发现任何真正有用的东西。是的,SSIS 方法是一种可能性,但问题需要一个存储过程。

      令我高兴的是,我(几乎)发现了原始问题想要的解决方案;您可以使用 CLR SP 来完成。

      将TableA中的数据选择到DataTable中,然后使用SqlBulkCopy类的WriteToServer(DataTable dt)方法,TableB为DestinationTableName。

      唯一的小缺点是 CLR 过程必须使用外部访问才能使用 SqlBulkCopy,并且不适用于上下文连接,因此您需要稍微调整一下权限和连接字符串。但是,嘿!没有什么是完美的。

      【讨论】:

        【解决方案5】:

        INSERT... SELECT... 的功能与BULK INSERT 非常相似。您可以像@GarethD 所说的那样使用 SSIS,但如果您只是将行从 table1 复制到 table2,那可能过于复杂。

        如果您要复制大量数据,请密切注意事务日志——在进行大量插入时,它可能会很快膨胀。一种解决方法是“分块”您正在插入的数据,方法是循环处理一次仅处理 100,000 或 10,000 行的插入语句(取决于行的宽度,即每次传递多少 MB)。

        (只是好奇,你是在用ALTER VIEW 重置视图吗?我曾经做过类似的事情,尽管我们必须有四个表和四个视图来支持过去/现在/下一个/交换集。)

        【讨论】:

        • 是的,我目前正在做 ALTER VIEW,但我想我会根据 Sylvia 的建议改用同义词。
        • 我撤回了这一点——视图似乎是一个更好的选择,因为它们提供了 ALTER 功能,其中同义词仅限于删除/创建。
        • 我迟到了,但是....如果您在事务中删除并创建同义词,它会显得原子
        【解决方案6】:

        你可以这样做

            select * into A from B Where [criteria]
        

        这将根据条件从 B 中选择数据并将其插入 A,前提是列相同,或者您可以指定列名而不是 *。

        【讨论】:

        • 他要求的是“散装”而不是常规负载。这个答案的问题是它会炸毁你的大额转账交易日志。最好使用 where 循环、CLR、SSIS 或 BULK INSERT 批量执行此操作,有时也是唯一的解决方案。
        • @AliRazeghi,请再过一遍问题,用户要求最快的方法是从一个表插入数据到另一个表,不管是简单的sql,批量插入,事务日志的可维护性问题。
        • 我不是对您的答案投反对票的人,但生产系统中的数百万行可能会根据隔离级别和硬件导致大量锁定/阻塞。这可能需要很长时间。 A select * into a from b 是最简单的答案,但不是最快的。
        猜你喜欢
        • 1970-01-01
        • 2013-06-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多