我有几个数据库管理任务需要遍历数据库中的每个记录。我的理解是,使用CakePHP 3.x ORM,我可以做这样的事情,并且它一次只能在内存中有一条记录:
$records = TableRegistry::get('Whatever')->find();
foreach ($records as $record) {
// do some processing
}
但是,这最终会因“内存不足”异常而崩溃。我添加了一些memory_get_peak_usage
的日志记录,并且每次迭代都会增加,即使除了foreach循环中发生的日志记录之外什么都没有。每次循环都会有大约12K的增量。
我正在运行3.2.7,无论是否启用了调试和/或SQL日志记录,结果都是类似的。添加对gc_collect_cycles()
的频繁调用只会减慢进程,但它对内存使用没有帮助。
这是预期的,还是一个错误?如果是前者,在这段代码中有什么我可以做的不同以防止它吗? (显然,我可以小批量处理它,但这不是一个优雅的解决方案。)
CakePHP 3.x ORM内置了ResultSet
对象的查询缓存。当您对结果集进行迭代时,实体将存储在内部数组中。这样做是为了让你可以倒回迭代器并再次循环。
如果您只想迭代一个大的结果集,并且想要减少内存使用,那么您必须禁用结果缓冲。
$records = TableRegistry::get('Whatever')->find()->bufferResults(false);
foreach ($records as $record) {
// do some processing
}
关闭缓冲后,实体将从结果集中获取,之后不应该对其进行引用。
CakePHP书中提供了此功能的文档:https://book.cakephp.org/3.0/en/orm/retrieving-data-and-resultsets.html#working-with-result-sets
这是API参考:https://api.cakephp.org/3.6/class-Cake.Database.Query.html#_bufferResults