【问题标题】:Saving memory when fetching large result sets with PDO使用 PDO 获取大型结果集时节省内存
【发布时间】:2011-03-11 01:26:35
【问题描述】:

我用 PHP 编写了一个用于数据库复制的工具。它工作正常,但有一个问题:

我正在使用 PDO 连接到不同的数据库,以使其独立于任何特定的 RDBMS,这对于此应用程序至关重要。

该工具对表格进行一些分析,以决定如何转换某些类型和其他一些东西。然后它几乎会执行“SELECT * FROM <tablename>”来获取需要复制的行。结果集相当大(在某些表中大约有 50k 行)。

之后,它使用PDOStatement::fetch(); 在while 循环中迭代结果集,进行一些类型转换和转义,构建INSERT 语句并将其提供给目标数据库。

除了一个例外,所有这些都运行良好。在一次一次地从结果集中获取行时,PHP 进程不断消耗越来越多的内存。我的假设是,PDO 将已处理的行保留在内存中,直到处理完整个结果集。

我还注意到,当我的工具完成一张表并继续下一张表时,内存消耗会立即下降,这支持了我的理论。

我不会将数据保存在 PHP 变量中!我在任何给定时刻都只保留一行进行处理,所以这不是问题。

现在问题是:有没有办法强制 PDO 不将所有数据保存在内存中?我一次只处理一行,所以绝对没有必要保留所有垃圾。我真的很想在这件事上使用更少的内存。

【问题讨论】:

    标签: php optimization memory pdo resultset


    【解决方案1】:

    我相信问题出在 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 可以生成独立于数据库的查询:

    $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
    

    【讨论】:

    • 也许这会有所帮助,但这只是 DBMS 特定的。该工具必须适用于多个数据库系统,任何非通用解决方案都太容易出错。我还认为将查询分成多个请求会降低整体性能。
    • 也许使用Zend_Db_Select 并生成独立于数据库的查询
    猜你喜欢
    • 1970-01-01
    • 2011-10-17
    • 2012-08-26
    • 2012-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-15
    • 2021-12-04
    相关资源
    最近更新 更多