因此,我们有一个现有的系统,我们试图扩大和运行内存,检索近3M记录。
我试图通过确定查询返回的数据大小,通过执行以下操作来确定增加服务器内存作为停止间隙解决方案的可行性:
select sum(row_size)
from (
SELECT
ifnull(LENGTH(qr.id), 0)+
ifnull(LENGTH(qr.question_id), 0)+
ifnull(LENGTH(qr.form_response_id), 0)+
ifnull(LENGTH(qr.`value`), 0)+
ifnull(LENGTH(qr.deleted_at), 0)+
ifnull(LENGTH(qr.created_at), 0)+
ifnull(LENGTH(qr.updated_at), 0)
as row_size
FROM
....
LIMIT 500000
) as tbl1;它返回30512865,大约是30 is的数据。
但是,当我交叉检查PHP实际使用什么来存储结果时,使用:
$memBefore = memory_get_usage();
$formResponses = DB::select($responsesSQL, $questionIDsForSQL);
$memAfter = memory_get_usage();
dd($memBefore, $memAfter);我得到了315377552和22403248,这意味着存储简单数组的292974304字节或大约300 of的内存使用量!
我想了解为什么内存占用是检索到的数据的10倍,除了修改后端和前端的API响应之外,我还能做些什么来减少内存占用吗?
对于上下文,当前实现使用上述结果(由getQuestionResponses返回)将其转换为由question_id使用Laravel集合分组的关联数组:collect($this->questionResponseRepo->getQuestionResponses($questions))->groupBy('question_id')->toArray();
我正在考虑用自己的实现替换collect,这将使用从查询返回的数组来通过将该数组转换为Laravel的Collection来降低内存膨胀,但这仍然无助于该数组本身占用300 of的500 k记录响应而不是30 of的记录响应。
在线解决方案之一是使用SplFixedArray,但我不知道如何强制DB::select使用它而不是数组?
另一种可能的解决方案是确保返回简单的assoc数组,而不是标准类https://stackoverflow.com/a/37532052/373091的数组,但当我尝试这样做时,如下所示:
// get original model
$fetchMode = DB::getFetchMode();
// set mode to custom
DB::setFetchMode(\PDO::FETCH_ASSOC);
$memBefore = memory_get_usage();
$formResponses = DB::select($responsesSQL, $questionIDsForSQL);
DB::setFetchMode($fetchMode);
$memAfter = memory_get_usage();
dd($memBefore, $memAfter, $formResponses);,我得到了错误Call to undefined method Illuminate\\Database\\MySqlConnection::getFetchMode(),这意味着它显然不能再从Laravel> 5.4 :(
有什么建议吗?
发布于 2022-09-08 17:34:14
我认为真正的问题是,您正在同时将所有300万条记录加载到内存中。相反,您应该以块的形式处理它们,或者使用游标。
块状
要将记录分批,可以使用Laravel的块块方法。该方法接受两个参数,即块大小和一个回调,该回调将传递用于处理的模型或对象的子集。这将在每个块的查询上执行。
下面是从文档中摘录的示例:
Flight::chunk(200, function ($flights) {
foreach ($flights as $flight) {
//
}
});游标
或者,如果只想执行单个查询,也可以使用游标方法。在这种情况下,Laravel一次只能补充一个模型,所以一次内存中永远不会有一个以上的模型(如果没有使用雄辩的话,也不会有多个对象)。
foreach (Flight::where('destination', 'Zurich')->cursor() as $flight) {
//
}https://stackoverflow.com/questions/73652637
复制相似问题