我在PHP中编写了一个用于数据库复制的工具。它工作正常,但有一个问题:
我正在使用PDO连接到不同的数据库,以使其独立于任何特定的RDBMS,这对此应用程序至关重要。
该工具对表进行一些分析,以决定如何转换某些类型和其他一些东西。然后它几乎用“SELECT * FROM <tablename>
”来获取需要复制的行。结果集相当大(某些表中大约有50k行)。
之后,它使用while
在PDOStatement::fetch();
循环中迭代结果集,执行某些类型转换和转义,构建INSERT
语句并将其提供给目标数据库。 / p>
所有这一切都很好地解决了一个例外。在从结果集中获取行时,PHP进程一直在占用越来越多的内存。我的结论是,PDO将已处理的行保留在内存中,直到处理完整个结果集。
我还注意到,当我的工具完成一个表并继续下一个表时,内存消耗会立即下降,这支持了我的理论。
我没有将数据保存在PHP变量中!我在任何给定时刻只持有一行进行处理,所以这不是问题。
现在提出一个问题:是否有办法强制PDO不要将所有数据保存在内存中?我一次只处理一行,所以绝对没有必要保留所有垃圾。我真的很想在这件事上少用内存。
答案 0 :(得分:2)
我认为问题来自php的垃圾收集器,因为它不会很快收集垃圾
我会尝试以row_count
大小的块来获取结果,例如MySQL中的"SELCT ... LIMIT offset, row_count"
或ORACLE中的"SELECT * FROM (SELECT ...) WHERE ROW_NUM BETWEEN offset AND (offset + row_count)"
。
使用Zend_Db_Select可以生成与DB无关的查询:
$select = $db->select()
->from(array('t' => 'table_name'),
array('column_1', 'column_2'))
->limit($row_count, $offset);
$select->__toString();
# on MySQL renders: SELECT column_1, column_2 FROM table_name AS t LIMIT 10, 20