yii2中不存在findall()方法,它是yii1遗留写法;正确做法是用find()->all()配合asarray()、each()或分页查询避免内存溢出。

Yii2中findAll()已废弃,别再用它了
Yii2里根本不存在findAll()这个方法——它是 Yii1 的遗留写法。现在调用它会直接报Fatal error: Call to undefined method,或者被自动降级为find()->all(),但后者在大数据量下极易触发内存溢出。你看到的“findAll内存溢出”,实际是ActiveQuery::all()把全部结果加载进内存并转成模型对象所致。
find()->all()为什么会吃光内存
每次调用all(),Yii2 不仅执行 SQL,还会为每行数据创建一个完整的ActiveRecord实例:挂载 behavior、绑定事件监听器、开启属性变更追踪、缓存原始属性快照……这些开销叠加起来,单条记录可能占 50–200KB 内存。查 10 万条?轻松突破 5GB,远超默认memory_limit。
- 即使只读字段,
ActiveRecord也会加载所有列(包括大文本、JSON 字段) - 模型间关联(
with())会让内存占用呈指数级增长 - 日志缓冲未及时刷盘(
flushInterval默认 1000)会额外堆积数 MB 日志对象
真正有效的替代方案
不改逻辑、不换框架,也能安全查 10 万+ 行:
- 强制数组结果:
(new Query)->from('user')->select(['id', 'name', 'status'])->limit(100000)->all($connection)—— 绕过 ActiveRecord,返回纯数组,内存恒定在 2–5MB - 游标式遍历:
User::find()->select(['id','email'])->each(100, function ($user) { /* 处理单条 */ });—— 每次只持有一批模型,内部自动释放前一批引用 - 手动分页处理:
for ($offset = 0; $offset offset($offset)->limit(500)->asArray()->all(); /* 处理 $rows */ unset($rows); gc_collect_cycles(); } - CLI 脚本必加:
Yii::getLogger()->flushInterval = 1;和'traceLevel' => 0,否则日志本身就能撑爆内存
容易被忽略的硬伤点
很多人试了asArray()还是溢出,问题往往卡在三个地方:
-
select()没精简字段,仍查了content、description等大字段 - 循环内反复调用
new User()或User::findOne(),哪怕加了unset(),behavior 里的闭包引用也阻止 GC - 数据库连接用了缓冲查询(PDO 默认),
all()会把整张表结果集一次性拖进 PHP 内存 —— 改用createCommand()->query()+fetch()逐行取更可控











