我有一个大事务,包括从数据库 A 获取大量数据,对这些数据进行一些操作,然后将操作后的数据插入数据库 B。我只有在数据库 A 中选择的权限,但我可以在数据库 B 中创建表并插入/更新等。
操作和插入部分是用 perl 编写的,并且已经用于从其他数据源将数据加载到数据库 B,因此所需要的只是从数据库 A 获取必要的数据并使用它来初始化 perl 类。
如果在操作或插入过程中发生任何错误(数据库断开连接、由于无效值导致的类初始化问题、硬盘故障),我该怎么做才能轻松地回溯并从发生错误的地方找出错误ETC...)?一次完成事务似乎不是一个好的选择,因为来自数据库 A 的数据量意味着至少需要一两天的时间来处理数据并将其插入数据库 B。
数据库 A 中的数据可以使用唯一键分为大约 1000 个组,每个键包含 1000 行。我认为我可以做的一种方法是编写一个脚本来按组提交,这意味着我必须跟踪哪个组已经插入到数据库 B 中。我能想到的唯一方法是跟踪哪些组的进度是否被处理要么在日志文件中,要么在数据库 B 的表中。我认为可行的第二种方法是转储加载类所需的所有必要字段以进行操作和插入到平面文件中,读取文件以进行初始化类并插入数据库 B。这也意味着我必须进行一些日志记录,但如果发生任何错误,应该将其缩小到平面文件中的确切行。该脚本看起来像这样:
use strict;
use warnings;
use DBI;
#connect to database A
my $dbh = DBI->connect('dbi:oracle:my_db', $user, $password, { RaiseError => 1, AutoCommit => 0 });
#statement to get data based on group unique key
my $sth = $dbh->prepare($my_sql);
my @groups; #I have a list of this already
open my $fh, '>>', 'my_logfile' or die "can't open logfile $!";
eval {
foreach my $g (@groups){
#subroutine to check if group has already been processed, either from log file or from database table
next if is_processed($g);
$sth->execute($g);
my $data = $sth->fetchall_arrayref;
#manipulate $data, then use it to load perl classes for insertion into database B
#.
#.
#.
}
print $fh "$g\n";
};
if ($@){
$dbh->rollback;
die "something wrong...rollback";
}
因此,如果确实发生任何错误,我可以再次运行此脚本,它应该会跳过已处理的组或行并继续。
这两种方法只是同一主题的变体,都需要回到我一直在跟踪我的进度的地方(在表或文件中),跳过已经提交到数据库 B 的那些并处理剩余的数据。
我确信有更好的方法可以做到这一点,但我正在努力寻找其他解决方案。有没有另一种方法来处理数据库之间的大型事务,这些事务需要在从一个数据库中取出数据和插入另一个数据库之间进行数据操作?该过程不需要全部使用 Perl,只要我可以重复使用 Perl 类来操作数据并将数据插入数据库即可。
最佳答案
很抱歉这么说,但我真的不明白你怎么可能通过走捷径来解决这个问题。对我来说,听起来您已经考虑了最合理的方法:
- 在每个步骤中将状态保存在某个临时表/文件中(我会查看“perldoc -f tie”或 sqlite)
- 正确处理错误 TryCatch.pm、eval 或任何你喜欢的
- 正确记录您的错误,即您可以阅读的结构化日志
- 将一些“恢复”标志添加到您的脚本中,该脚本读取以前的日志和数据并重试
这可能与您一直在思考的思路一致,但正如我所说,我认为没有通用的“正确”方法来处理您的问题。
关于sql - 使用 perl dbi 处理长时间运行的大事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12229091/