【问题标题】:How to get data from big table row by row如何逐行从大表中获取数据
【发布时间】:2018-11-25 06:43:59
【问题描述】:

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

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

但总有一个但是……

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

我的问题是:

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

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

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

【问题讨论】:

标签: mysql perl dbi


【解决方案1】:

显然查询的所有结果在执行()命令后都存储在内存中

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

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

【讨论】:

  • 太棒了!谢谢你。这正是我正在寻找的;)
【解决方案2】:

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

以下代码一次从表中读取 1000 行并处理每一行

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);
    }
}

【讨论】:

  • 不幸的是,这个解决方案并不能解决内存问题。执行后所有数据都存储在内存中......这不是我要找的,但仍然谢谢。
【解决方案3】:

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

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

Application会根据自己处理的每个Package动态填写$lastid

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

【讨论】:

    猜你喜欢
    • 2017-05-05
    • 2018-05-29
    • 2021-08-24
    • 2016-03-01
    • 2017-08-21
    • 1970-01-01
    • 1970-01-01
    • 2011-04-12
    • 1970-01-01
    相关资源
    最近更新 更多