具体情景
- laravel ORM中的cursor游标
cursor方法允许你使用游标遍历数据库,它只执行一次查询。处理大量的数据时,可以大大减少内存的使用量- 通过对比
cursor与get方法,查找到了其中的一点不同,get方法是直接fetchAll返回所有数据,cursor方法是使用yield构建了一个生成器,逐步返回fetch的数据
- PDO mysql中的查询
- 一般查询如下:
$sql = "select * from `user` limit 100000000"; $stat = $pdo->query($sql); $data = $stat->fetchAll(); //mysql buffered直接全部返回给php var_dump($data); - 使用
yield如下:function get(){ $sql = "select * from `user` limit 100000000"; $stat = $pdo->query($sql); while ($row = $stat->fetch()) { //一个一个地返回给php yield $row; } } foreach (get() as $row) { var_dump($row); }
- 一般查询如下:
- PDO参数
- 查看php手册MYSQL_ATTR_USE_BUFFERED_QUERY
- 这个PDO参数,侧面说明了,如果这个参数为
ture,MySQL驱动程序将使用MySQL API的缓冲版本。 - 注意,这个参数只对Mysql起作用,如果要编写可移植的sql代码,请使用
fetchAll
- 这个PDO参数,侧面说明了,如果这个参数为
- 查看php手册MYSQL_ATTR_USE_BUFFERED_QUERY
在使用了yield的情况下,内存使用量的确减少了,但是在逐渐使用yield中,内存会逐渐增大,这样的情况与以下函数不一致,下面这个函数的内存使用量将会不变
function getNum() {
for($i=0; $i < 100000000; $i++) {
yield $i;
}
}
结论
在使用fetch、fetchAll之前,查找数据结果集还存在于mysql的缓冲区内,而每次yield和fetch配合,才取回一条结果存入内存,这就能解释,为什么内存使用量会逐步增大
而上面的这个getNum函数之所以内存使用量不变,是因为,每次只返回一个数字
这里面有点矛盾之处,感觉跟php的垃圾回收有点关系,暂时未深究