尽管限制和偏移查询,PHP 仍会耗尽内存

问题描述 投票:0回答:1

背景

加载时包含许多连接、选择和诸如此类的原始 SQL 查询

$results = DB::SELECT($query)

创建了约 500mb、450,000 个项目

$results
集合,这不好。

解决方案

因此 $query 现在改为创建一个临时表,可以通过以下方式读取该临时表:

$new_rows = true;
$chunk = 25000;
$offset = 0;

while ($new_rows) {
    $chunked_results = DB::SELECT('SELECT * FROM tmp_table ORDER BY id DESC LIMIT ' . $chunk . ' OFFSET ' . $offset );
    
    if (count($chunked_results) === 0) {
        $new_rows = false;
    }
    
    foreach ($chunked_results as $row) {
        //Do stuff with $row
    }

    $offset+= $chunk;
    unset($chunked_results);
}

问题

尽管在每次查询后取消设置

$chunked_results
,我的脚本仍然在第 75,000 行左右耗尽内存 - 几乎相同。加载的行数没有分块/tmp_table。

这让我相信,不知何故,之前

$chunked_results
的内容保留在内存中,并且不会真正取消设置,或者
DB::class
会记住后台的内容。

执行

DB::RECONNECT('mysql')
会消灭临时表:(

php mysql mariadb laravel-10
1个回答
0
投票
随着它变大,

OFFSET
变得越来越慢。 这是因为查询必须跳过越来越多的行。

相反,“在

WHERE
的帮助下记住你离开的地方。” 讨论:https://mysql.rjweb.org/doc.php/deletebig#deleting_in_chunks就您而言,
WHERE id > $the_last_id_of_prev_query
听起来很合适。

我不建议使用大于 1000 行的块,因为您可能会遇到其他限制。 (>1000 就进入“收益递减”状态。)

© www.soinside.com 2019 - 2024. All rights reserved.