Arrays 用perl并行处理将数组项写入数据库

Arrays 用perl并行处理将数组项写入数据库,arrays,database,perl,parallel-processing,Arrays,Database,Perl,Parallel Processing,我有一个用perl编写的程序(在Linux下运行的perl版本5.10.1),可以生成一个数组。数组的每个条目都是另一个数组。最后的每个数组都包含一组7个值,我需要将这些值写入数据库。目前,我在数组上运行一个循环,并将信息写入数据库。由于这些写操作是相互独立的,所以我认为可以并行运行多个进程 下面是我目前使用的基本循环,我想将其拆分为并行进程。我需要并行执行此操作,因为数组的初始数组包含大约100000个条目,将条目添加到数据库大约需要30分钟 for my $icell (0 .. scala

我有一个用perl编写的程序(在Linux下运行的perl版本5.10.1),可以生成一个数组。数组的每个条目都是另一个数组。最后的每个数组都包含一组7个值,我需要将这些值写入数据库。目前,我在数组上运行一个循环,并将信息写入数据库。由于这些写操作是相互独立的,所以我认为可以并行运行多个进程

下面是我目前使用的基本循环,我想将其拆分为并行进程。我需要并行执行此操作,因为数组的初始数组包含大约100000个条目,将条目添加到数据库大约需要30分钟

for my $icell (0 .. scalar @Sheet_Cells_Data-1){
    my $Cell_Data_INTER1=$Sheet_Cells_Data[$icell];
    my @Cell_Data=@$Cell_Data_INTER1;
    $insert_to_db->execute($Cell_Data[0],$Cell_Data[1],$Cell_Data[2],$Cell_Data[3],$Cell_Data[4],$Cell_Data[5],$Cell_Data[6]);
}
那么,这是否可能?如果可能,我将如何着手实现这一目标

非常感谢您的帮助


Chazg76

看起来您可能正在使用SQLite?在这种情况下,您可能会发现这很有用

如果使用的是DBI.pm,则可以通过使用占位符准备insert语句一次,然后执行多次来加快插入速度

$sth = $dbh->prepare(“insert into table values (?,?,?,?,?,?,?)”);
for my $icell (0 .. $#Sheet_Cells_Data){
    my $Cell_Data_INTER1=$Sheet_Cells_Data[$icell];
    my @Cell_Data=@$Cell_Data_INTER1;
    $sth->execute(@Cell_Data[0]);
}
我发现这提供了一些速度,但是按照choroba的建议将数据写入以制表符分隔的文件并使用

LOAD DATA INFILE '/home/user/data/table.tsv' INTO TABLE db_table
对于大多数RDBMS来说,这是高度优化的


确保为输入文件提供完整的路径,因为默认路径通常是RDBMS使用的特权目录。看起来您可能正在使用SQLite?在这种情况下,您可能会发现这很有用

如果使用的是DBI.pm,则可以通过使用占位符准备insert语句一次,然后执行多次来加快插入速度

$sth = $dbh->prepare(“insert into table values (?,?,?,?,?,?,?)”);
for my $icell (0 .. $#Sheet_Cells_Data){
    my $Cell_Data_INTER1=$Sheet_Cells_Data[$icell];
    my @Cell_Data=@$Cell_Data_INTER1;
    $sth->execute(@Cell_Data[0]);
}
我发现这提供了一些速度,但是按照choroba的建议将数据写入以制表符分隔的文件并使用

LOAD DATA INFILE '/home/user/data/table.tsv' INTO TABLE db_table
对于大多数RDBMS来说,这是高度优化的


请确保为输入文件提供完整的路径,因为默认路径通常是RDBMS使用的特权目录,实现此并行处理的一种方法是使用fork。 像下面这样

假设我们将使用5个并行进程来完成插入工作。代码如下:

my $max_proc   = 5;
my $batch_size = scalar @Sheet_Cells_Data / $max_proc;
my $start_point = 0;

for (1 .. $max_proc) {
    if (fork()) {
        #In Parent
        $start_point += $batch_size;
    } else {
        #In Child
        my $end_point = $start_point + $batch_size -1;
        for my $i ($start_point .. $end_point){
           #Do you insert work here
        }

        exit;
    }
}
需要注意的几点:

1. Wait for all the child process to finish before parent process ends.
2. You might have to initialize new database connection in each child and close them before child process ends.

实现这种并行处理的一种方法是使用fork。 像下面这样

假设我们将使用5个并行进程来完成插入工作。代码如下:

my $max_proc   = 5;
my $batch_size = scalar @Sheet_Cells_Data / $max_proc;
my $start_point = 0;

for (1 .. $max_proc) {
    if (fork()) {
        #In Parent
        $start_point += $batch_size;
    } else {
        #In Child
        my $end_point = $start_point + $batch_size -1;
        for my $i ($start_point .. $end_point){
           #Do you insert work here
        }

        exit;
    }
}
需要注意的几点:

1. Wait for all the child process to finish before parent process ends.
2. You might have to initialize new database connection in each child and close them before child process ends.

你使用什么数据库?它可能支持“批量加载”,这通常是加载数据的最快方式。在这种情况下,您可以使用Perl将数据转换为受支持的格式,然后运行批量加载。但是,从根本上说,如果数据库正在执行“工作”,那么并行化脚本是没有帮助的。作为旁注,Perl 5.10.1于2007年发布,这将使该版本有10年的历史。另一个需要注意的问题可能是(自动)提交设置。如果可能,尝试将
autocommit
设置为false,然后每隔1000行左右提交一次。通常这会有很大帮助。你使用什么数据库?它可能支持“批量加载”,这通常是加载数据的最快方式。在这种情况下,您可以使用Perl将数据转换为受支持的格式,然后运行批量加载。但是,从根本上说,如果数据库正在执行“工作”,那么并行化脚本是没有帮助的。作为旁注,Perl 5.10.1于2007年发布,这将使该版本有10年的历史。另一个需要注意的问题可能是(自动)提交设置。如果可能,尝试将
autocommit
设置为false,然后每隔1000行左右提交一次。这通常很有帮助。