通过 Yii 框架从数据库导出大批量数据


最近有客户想一次性把客户的客资数据导出备份,经过几年的使用,很多客户的客资量都接近百万,如果要一次性导出这么多量,就不能直接从数据库读取放到数组里面,一个是 php 默认会限制内存使用量,另外内存也不应该浪费在这个上面。

Yii 框架提供了 BatchQueryResult 对象,该对象实现了 Iterator 接口,这样从数据库获取数据不会受限于内存,影响系统的稳定了。

环境说明:PHP 7.2

$unbufferedDb = new \yii\db\Connection([
    'dsn' => Yii::$app->pc->dsn,
    'username' => Yii::$app->pc->username,
    'password' => Yii::$app->pc->password,
    'charset' => Yii::$app->pc->charset,
]);
$unbufferedDb->open();
$unbufferedDb->pdo->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);

$query = Leads::find()->all();
foreach ($query->each(50, $unbufferedDb) as $item) {
    // 这里就可以一个个处理数据(还原中文显示,其他关联的数据)并写入文件中
}

每次遍历 50 个客资进行处理,关于 $unbufferedDb ,Yii 官方文档也有说明(p1),测试下来把 MYSQL_ATTR_USE_BUFFERED_QUERY 设置为 false,内存使用量才是正常的。

[图片:p1] p-1

[图片:p2] p-2

[图片:p3] p-2

图片 p2 和 p3 分别是导出时的进程,MYSQL_ATTR_USE_BUFFERED_QUERY 分别为 falsetrue,通过 memory_get_usage 函数内存占用基本相同,但看进程内存占用是不一样的,一个 0.5%、一个 6%。

Yii 文档里面提到的 libmysqlclient 库,php 5.4 之后编译时默认改成了 mysqlnd