【问题标题】:copying a very large table from one DB2 to another, using perl and DBI使用 perl 和 DBI 将一个非常大的表从一个 DB2 复制到另一个
【发布时间】:2013-01-08 23:26:21
【问题描述】:

我需要每天将一个非常大(数百万行)的表从一个 DB2 DB 复制到另一个,并且我需要使用 perl 和 DBI。

有没有比从第一个 DB 中简单地 fetchrow_array 每一行并将它们一个接一个插入第二个 DB 更快的方法?这是我得到的:

$sth1 = $udb1 -> prepare($read_query);
$sth1 -> execute();
$sth1 -> bind_columns(\(@row{@{$sth1 -> {NAME_1c}}}));

$sth2 = $udb2 -> prepare($write_query);

while ($sth1 -> fetchrow_arrayref) {
    $sth2 -> execute($row{field_name_1}, $row{field_name_2});
}

我从一个类似的线程中实现了一些解决方案,但它仍然很慢。肯定有更好的方法吗?

【问题讨论】:

    标签: sql perl transactions db2 dbi


    【解决方案1】:

    如果你把它包装到一个事务中,它应该工作得更快。 使用这样的东西:

    $sth1 = $udb1->prepare($read_query);
    $sth1->execute();
    $sth1->bind_columns(\(@row{@{$sth1->{NAME_1c}}}));
    
    $udb2->begin_work();
    $sth2 = $udb2->prepare($write_query);
    while ($sth1->fetchrow_arrayref()) {
        $sth2->execute($row{field_name_1}, $row{field_name_2});
    }
    $udb2->commit();
    

    如果您有数百万行,您可能希望每几千行执行一次提交。

    现在,它更快的原因:

    在您的情况下,每个插入都是一个自动提交的事务。换句话说,服务器必须等到您的更改真正刷新到数百万行中的每一行 - 非常慢!

    当您将其包装到事务中时,服务器可以一次将数千行刷新到磁盘 - 效率更高、速度更快。

    (如果您一遍又一遍地复制完全相同的表,那么通过某种唯一键同步更改会更明智 - 应该快一百万倍)。

    【讨论】:

    • 啊哈。那太棒了。我想这很简单。非常感谢。
    【解决方案2】:

    除了 mvp 在这里所说的之外,还有来自 DBI 文档的 sn-p:

     my $sel = $dbh1->prepare("select foo, bar from table1");
      $sel->execute;
    
      my $ins = $dbh2->prepare("insert into table2 (foo, bar) values (?,?)");
      my $fetch_tuple_sub = sub { $sel->fetchrow_arrayref };
    
      my @tuple_status;
      $rc = $ins->execute_for_fetch($fetch_tuple_sub, \@tuple_status);
      my @errors = grep { ref $_ } @tuple_status;
    

    当与 mvp 的答案结合使用时,它应该会更快,特别是如果 DBD::DB2 有自己的 execute_for_fetch 方法(我不知道)。具有自己的 execute_for_fetch 方法的 DBD 通常会批量操作。不过,无论如何,它应该会快一点。

    【讨论】:

      【解决方案3】:

      如果您每天都这样做,我会认为 DB2 的 exportimport 实用程序将是可行的方法。这种方式可能比多个 SQL INSERT 语句快很多

      您可以使用 Perl 的 DBI 模块执行此操作,但如果您需要在 Perl 脚本中完成此操作,则可能必须使用 system 或反引号。

      【讨论】:

      • 这有点像我最初的问题。我实际上是(1)删除旧表中的所有数据,(2)用所有新数据替换它。最终结果是完全相同的表。因此,如果可能的话,通过 DBI 进行导出/导入会更有意义。
      【解决方案4】:

      如果您可以将源数据库中的内容发送到文件,您可以使用 LOAD 命令或 INGEST 实用程序。 LOAD 非常快,因为它不使用日志。 INGEST是正常插入,但可以重启。

      这些命令可以从 Perl 中调用,其余的由 DB2 完成。

      但是,如果源数据库和目标数据库是 DB2,您可以在目标中联合源。这意味着,您可以在目标数据库中看到远程表(来自源)。在这种情况下,您只需要调用 LOAD,就可以了。它会最快,因为通信是在 DB2 和 DB2 之间,而不是像这样 DB2 -> Perl -> DB2。

      我认为让 DB2 来处理大表会更好,因为中间有 Perl。内存可能会爆炸,提交可能是一个问题,等等。

      另外,根据您的 DB2 许可,您可以使用 Optim High Performance Unload,以便直接从表空间中提取表,而不是通过 SQL(较慢)。

      【讨论】:

      • 这似乎是迄今为止最好的建议。但是来自联合源的 LOAD 如何工作?据我了解,LOAD 仅接受文件(或等效文件)作为输入。
      • 从游标加载,游标定义在联合表上(昵称)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-05
      • 1970-01-01
      • 2020-05-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多