如何逐行从大 table 中获取数据

How to get data from big table row by row

我需要从 mysql table 获取所有数据。到目前为止我尝试过的是:

my $query = $connection->prepare("select * from table");
$query->execute();
while (my @row=$query->fetchrow_array)
{
    print format_row(@row);
}

但总有一个但是...

Table 有大约 600M 行,显然所有查询结果都在 execute() 命令后存储在内存中。内存不足:(

我的问题是:

有没有办法使用 perl DBI 从 table 逐行获取数据?像这样:

my $query = $connection->prepare("select * from table");
while (my @row=$query->fetchrow_array)
{
    #....do stuff
}

顺便说一句,分页速度很慢:/

fetchall_arrayref 方法有两个参数,第二个参数允许您限制一次从 table 中获取的行数

以下代码一次从 table 中读取 1,000 行并处理每一行

my $sth = $dbh->prepare("SELECT * FROM table");
$sth->execute;

while ( my $chunk = $sth->fetchall_arrayref( undef, 1000 ) ) {

    last unless @$chunk;    # Empty array returned at end of table

    for my $row ( @$chunk ) {

        print format_row(@$row);
    }
}

apparently all results from query is store in memory after execute() command

这是 mysql 客户端库的默认行为。您可以通过在数据库或语句句柄上使用 mysql_use_result attribute 来禁用它。

请注意,当所有行都流式传输到客户端代码时,您在 table 上的读锁将保持更长的时间。如果这可能是一个问题,您可能需要使用 SQL_BUFFER_RESULT.

在使用大表时,我使用动态构建的 SQL 语句构建数据包,例如

$sql = "SELECT * FROM table WHERE id>" . $lastid . " ORDER BY id LIMIT " . $packagesize

应用程序将根据它处理的每个包动态填写$lastid

如果 table 有一个 ID 字段 id 它也有一个建立在该字段上的索引,因此性能非常好。
它还通过每个查询之间的小休息来限制数据库负载。