一次提交添加八千行

Add eight thousand line in one commit

我有一个日志文件,获取日志文件并转录日志文件的 perl 脚本,我想在一次提交中发送所有行(八千行)

我的脚本:

# Connect to the database.
my $dbh = DBI->connect(
    "DBI:mysql:database=DB;host=>IP",
    "hostname", 'password',
    {'RaiseError' => 1,'AutoCommit'=> 0}
);

    open (FILE, 'file.log');
    while (<FILE>) {

        ($word1, $word2, $word3, $word4, $word5, $word6, $word7, $word8, $word9, $word10, $word11, $word12, $word13, $word14) = split(" ");

        $word13 =~ s/[^\d.]//g;
        if ($word2 eq "Feb") {
                $word2 = "02"  
        }

        print "'$word5-$word2-$word3 $word4', $word11, $word13 \n";

        eval {
            #on peut utiliser insert mais il y aura des doublons et ici on est dans une table unique
            my $sth = $dbh->prepare("INSERT INTO `test_query` (time, cstep, time_in_seconde) VALUES('$word5-$word2-$word3 $word4', $word11, $word13);");

            #print $sth->rows . " rows found.\n";
            #$sth->finish;          

            # do inserts, updates, deletes, queries here
            #$sth->execute() or die "execution failed: $dbh->errstr()";
            $sth->execute() or die "execution failed: $dbh->errstr()";
            $dbh->commit();

        };

        ### If something went wrong...

    }
}

$dbh->disconnect();

谢谢

为了获得更好的性能,您希望简化代码并将尽可能多的代码移出循环:

  • prepare语句跳出循环,使用绑定参数:语句总是一样的,只有绑定参数得到改变

  • commit 退出循环:这将提高性能,并且还具有使您的过程 原子化 的优势。由于所有更改都发生在同一个数据库事务中,因此所有行都将被处理(并提交),或者,如果任何行发生故障,则根本不会提交任何行。在实施此优化时,您需要注意数据库的资源使用情况(这通常需要 UNDO tablespace 中的更多 space);如果资源不够,要么增加它们,要么提交每第 N 条记录(N 尽可能高)

  • 避免在循环中 printing 除非你真的需要它(我评论了那行)

  • 您正在建立一个启用了 RaiseError 属性的连接,但是您忽略了 execute 处可能发生的错误。如果这真的是你想要的,那么只需禁用语句处理程序上的 RaiseError 属性,并删除 execute

  • 周围的 eval

编码实践方面的其他注意事项:

  • 总是use strictuse warnings

  • 使用数组而不是标量列表来存储解析的数据:可以使您的代码更快并且 使其更具可读性

代码:

use strict;
use warnings;

# Connect to the database.
my $dbh = DBI->connect(
    "DBI:mysql:database=DB;host=>IP",
    "hostname", 'password',
    {'RaiseError' => 1,'AutoCommit'=> 0}
);

# prepare the insert statement
my $sth = $dbh->prepare("INSERT INTO `test_query` (time, cstep, time_in_seconde) VALUES(?, ?, ?)");
$sth->{RaiseError} = 0;

open (my $file, 'file.log') or die "could not open : $!";
while (<$file>) {
    my @words = split / /;
    $words[12] =~ s/[^\d.]//g;
    if ($words[1] eq "Feb") {
            $words[1] = "02" ;
    }

    # print "'$words[4]-$words[1]-$words[2] $words[3]', $words[10], $words[12] \n";
    $sth->execute( "$words[4]-$words[1]-$words[2] $words[3]", $words[10], $words[12] );

}

$dbh->commit;
$dbh->disconnect;

最后一个解决方案,可能比这个执行得更快,是使用 DBI method execute_array 执行批量数据库插入。属性 ArrayTupleFetch 可用于提供 DBI 每次准备好执行下一个 INSERT 时将调用的代码引用:此代码引用应读取下一个文件行并提供值 sui[ 的数组引用=75=] 对于 INSERT。当文件耗尽时,sub 应该 return undef,这将指示 DBI 批量处理已完成。

代码:

#!/usr/local/bin/perl

use strict;
use warnings;
use DBI;

# open the file
open (my $file, 'log.file') or die "could not open : $!";

# connect the database
my $dbh = DBI->connect("DBI:mysql:database=DB;host=ip", "hostname", 'password', {'RaiseError' => 1,'AutoCommit'=> 0});

# prepare the INSERT statement
my $sth = $dbh->prepare("INSERT INTO `test_query` (time, cstep, time_in_seconde) VALUES(?, ?, ?)");

# run bulk INSERTS
my $tuples = $sth->execute_array({ 
    ArrayTupleStatus => \my @tuple_status,
    ArrayTupleFetch => sub {
        my $line = <$file>;
        return unless $line;
        my @words = split / /;
        # ... do anything you like with the array, then ...
        return [ "$words[4]-$words[1]-$words[2] $words[3]", $words[10], $words[12] ];
    }
});

if ($tuples) {
    print "Successfully inserted $tuples records\n";
} else {
    # do something usefull with @tuple_status, that contains the detailed results
}

$dbh->commit;
$dbh->disconnect;