我们平时用
while ($row = mysql_fetch_assoc($result)) {
// …
}
这种常见的问题的话我们可以采取不同的方法得意解决。 不过, 就这个问题来讲, 我首先想到, MySQL是常见的C/S(Client/Server, 客户端/主机)模型, 在得出结果的时候, 底层设计可能是否把数据听过网络的形式(如果有使用TCP/IP)读到了Client的缓冲区, 还有一种可能, 我们需要是数据还在Server端的发送缓冲区, 并没有传递到Client.
在查看PHP和MySQL的源码之前, 我注意到PHP手册里有两个功能相近的函数:
mysql_query()
mysql_unbuffered_query()
通过两个函数的实验验证了我的想法, 操作第一个函数执行的时候, 结果集从Server端转移到Client端的缓冲区, 而后一个则没有, 这就是“unbuffered(未缓冲)”的意思。
那就是说, 如果用mysql_unbuffered_query()执行了一条返回大量结果集的SQL语句, 在结果还没出来的时候, PHP的内存是没有被结果集占用的。 而用mysql_query()来执行相同的代码, 函数执行返回时, PHP的内存占用会迅速增加, 内存很快就占用完。
如果阅读PHP的相关代码, 可以看到这两个函数的实现上的异同:
/* {{{ proto resource mysql_query(string query [, int link_identifier])
Sends an SQL query to MySQL */
PHP_FUNCTION(mysql_query)
{
php_mysql_do_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQL_STORE_RESULT);
}
/* }}} */
/* {{{ proto resource mysql_unbuffered_query(string query [, int link_identifier])
Sends an SQL query to MySQL, without fetching and buffering the result rows */
PHP_FUNCTION(mysql_unbuffered_query)
{
php_mysql_do_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQL_USE_RESULT);
}
/* }}} */
两个函数都有用php_mysql_do_query(), 其中只有第2个参数的不同, MYSQL_STORE_RESULT和MYSQL_USE_RESULT. 继续观察php_mysql_do_query()的实现:
if(use_store == MYSQL_USE_RESULT) {
mysql_result=mysql_use_result(&mysql-》conn);
} else {
mysql_result=mysql_store_result(&mysql-》conn);
}
mysql_use_result()和mysql_store_result()是MySQL的C API函数, 这两个C API函数的区别就是后者把结果集从MySQL Server端全部传递到了Client端, 前者只是读取了结果集的元信息。
我们回头看看PHP, 应用mysql_unbuffered_query(), 相对来说可避免立即占用。 如果在编辑的过程不对结果进行“PHP缓存”(如放到某数组中), 则整个执行过程虽然操作了十万条或者百万条或者更多的数据, 但PHP占用的内存一般都是比较少的。
(广力