【问题标题】:Add eight thousand line in one commit [closed]在一次提交中添加八千行 [关闭]
【发布时间】:2019-05-11 02:58:36
【问题描述】:

我有一个日志文件,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();

谢谢

【问题讨论】:

  • 所以Feb 被转换为02,但是March 呢?
  • 有什么问题或疑问?
  • 我的问题是如何一次放千行
  • 不知道为什么它被关闭了,因为不清楚。 OP 询问如何将多行添加为一个事务,答案涵盖了这一点。

标签: linux windows perl sql-insert query-performance


【解决方案1】:

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

  • prepare循环外的语句,使用绑定参数:语句总是一样的,只有绑定参数才能改变

  • commit 退出循环:这将提高性能并且还具有使您的流程原子的优势。由于所有更改都发生在同一个数据库事务中,因此将处理(并提交)所有行,或者,如果任何行发生故障,则根本不会提交任何行。在实现此优化时,您需要注意数据库上的资源使用情况(这通常需要UNDO 表空间中的更多空间);如果资源不够,要么增加它们,要么每第 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 时调用的代码引用:此代码引用应读取下一个文件行并提供适合 INSERT 的值的数组引用。当文件耗尽时,sub 应该返回 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;

【讨论】:

  • 谢谢,我收到这条消息 DBD::mysql::st execute failed: 在 test_request.pl 第 104 行, 第 1 行需要 0 时使用 1 个绑定变量调用。 DBD::mysql ::st 执行失败:当 test_request.pl 第 104 行, 第 1 行需要 0 时,使用 1 个绑定变量调用。由于 DESTROY 没有明确的 DBD::mysql::db 句柄数据库的断开连接()而发出回滚() =slow_transdb;host=ip at test_requ
  • @dfg ert,该错误并非来自 GMB 的代码。当需要 3 个值时,GMB 的代码提供 3 个值(不是您声称的 0 和 1)
  • 我有新消息 @ikegami DBD::mysql::st 执行失败:在 test_request.pl 第 96 行, 第 1 行需要 0 时使用 3 个绑定变量调用。DBD::mysql ::st 执行失败:在 test_request.pl 第 96 行, 第 1 行需要 0 时使用 3 个绑定变量调用。由于没有显式断开连接()的 DESTROY,发出回滚()
  • 仍然不是来自 GBD 的代码。该错误意味着您正在使用的查询中没有?,但您将三个参数传递给execute。在GBD的代码中,查询中有三个?,三个参数传递给execute
  • 正如@ikegami 所解释的,这不是其中的查询INSERT query I gave you (mine has 3 ?`,你的没有)。请正确复制我的答案中的代码,然后进行测试。
猜你喜欢
  • 2019-04-19
  • 1970-01-01
  • 2012-04-08
  • 1970-01-01
  • 1970-01-01
  • 2019-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多