【问题标题】:Perl many insert statments into mysql databasePerl 许多插入语句到 mysql 数据库中
【发布时间】:2015-08-19 17:19:42
【问题描述】:

我目前的 perl 代码如下所示:

@valid = grep { defined($column_mapping{ $headers[$_] }) } 0 .. $#headers;

...

my $sql = sprintf 'INSERT INTO tablename ( %s ) VALUES ( %s )',
  join( ',', map { $column_mapping{$_} } @headers[@valid] ),
  join( ',', ('?') x scalar @valid);
my $sth = $dbh->prepare($sql);

...

my @row = split /,/, <INPUT>; 
$sth->execute( @row[@valid] );

(取自 mobanswer 到上一个问题。)

这基本上是从 csv 数据动态构建一个 sql insert 语句,并且只允许从我的列映射中选择具有正确标题的 csv 数据。

我一直在寻找有关如何一次对多行数据执行插入语句的示例。

我的 perl 脚本需要运行大约几亿条插入语句,而且一次执行一个似乎真的很慢,特别是因为我运行它的服务器只有 6gb 的内存和缓慢的互联网连接。

有没有一种方法可以一次上传多于 1 行的数据?所以一个插入语句可能一次上传 50 行或 100 行?我不知道如何使用 perl DBI。

【问题讨论】:

  • @ThisSuitIsBlackNot 那是我在上面找到的唯一一个,而那家伙建议一次做一个,大多数其他 cmets 都同意,这不是我想要的。他说他不会使用这种方法来执行多个插入语句,大多数答案都说一次执行一个。我想知道是否有一个不是那个的答案
  • 阅读已接受答案中的第一种方法,以“您可以根据数组的大小多次插入(?, ?, ?)”开头。这显示了如何为多行生成单个插入语句。
  • 与副本无关:DBI 脚本中的一个常见性能问题是在循环中调用prepare;您还没有显示所有代码,所以我不知道您是否属于这种情况,但您应该确保只为给定查询调用一次 prepare
  • 另外,如果您要插入大量行,LOAD DATA INFILE 可能会比一系列复合插入更快。为此,请像现在一样解析原始数据并将其写入 CSV 文件,然后使用 LOAD DATA INFILE 加载它。在这一点上,这种方法是否比复合插入更快取决于您的应用程序和数据库设置,但您可以通过这种方式获得显着的性能提升。

标签: mysql sql perl sql-insert dbi


【解决方案1】:
my $sql_values = join( ' ', ('(?, ?, ?)') x scalar(@array) );

如前所述,那么您可以将其展平。

【讨论】:

    【解决方案2】:

    您可以使用与常规 SQL 相同的语法一次插入多行,但您需要使用 Perl 正确构建 INSERT 语句。 Perl 的 slice() 可以帮助你:

    假设您有 7 行数据并希望将它们插入到 3 行的块中。 “常规”SQL 是这样的:

    insert into T (col1, col2) values ( 1, 2), ( 3, 4), ( 5, 6);
    insert into T (col1, col2) values ( 7, 8), ( 9,10), (11,12);
    insert into T (col1, col2) values (13,14);
    

    假设你的 perl 结构是这样的:

    my $values = [ [1,2], [3,4], ..., [13,14] ];
    

    如果不是,把它变成这个形状。现在:

    use constant CHUNKSIZE => 3;
    
    my $stmt = sprintf( 'insert into T (col1, col2) values %s', 
                        join(',', '(?,?)' x CHUNKSIZE) );
    # $stmt is now 'insert into T (col1, col2) values (?,?),(?,?),(?,?)'
    
    my $sth = $dbh->prepare($stmt);
    
    while( my @chunk = splice( @{$values}, 0, CHUNKSIZE ) ) {
        # @chunk has 3 elements (rows), or less for the last chunk
        if (scalar @chunk == CHUNKSIZE) {
            $sth->execute( @chunk ); # inserts 3 rows at once
        } else {
            # build and prepare a new statement for the remaining rows.
            # in our sample there is only 1 remaining row.
            $stmt = sprintf( 'insert into T (col1, col2) values %s',
                             join(',', '(?,?)' x scalar @chunk) );
            $sth = $dbh->prepare($stmt);
            $sth->execute( @chunk ); # inserts the last row
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-19
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      相关资源
      最近更新 更多