PHPがMySQLの大量データを検索する時メモリ占有分析
1829 ワード
昨日、同僚がPHP討論グループで彼がやったプロジェクトはMySQLクエリの結果が多すぎて、PHPメモリが足りなくなりました。だから、彼は下記のコードを実行する前に、データはすでにメモリにありましたか?
while ($row = mysql_fetch_assoc($result)) {
// ...
}
はもちろん、このような問題には多くの最適化の方法があります。しかし、この問題に関して、まず、MySQLは古典的なC/Sモデルであり、結果集を巡回する前に、底層の実現はすでにすべてのデータをネットワーク(TCP/IPを使うと仮定して)に通してCientのバッファエリアに読んだかもしれません。他の可能性もあります。データはまだServer端の送信バッファにあり、Clientに伝えられていません。PHPとMySQLのソースコードを確認する前に、PHPマニュアルには二つの機能が似ている関数があることに気づきました。もう一つはないです。これは「unbuffered」という意味です。つまり、mysqlを使うとunbuffered_query()は大量の結果セットに戻るSQL文を実行しました。結果を遍歴する前に、PHPのメモリは結果セットによって占有されませんでした。mysql_を使います。query()が同じ文を実行すると、関数が戻るとPHPのメモリ占有率が急激に増加し、直ちにメモリが消耗します。PHPの関連コードを読むと、この2つの関数の実現上の違いが見られます。
mysql_query()
mysql_unbuffered_query()
の関数はいずれもphp_を呼び出しました。mysqlドドドドquery()は、2番目のパラメータだけが違っています。MYSQL_STORE_RESULTとMYSQL_USE_RESULT.更にphp_を見ますmysqlドドドドquery()の実現:
/* {{{ 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);
}
/* }}} */
mysql_アメリカ.レスリングとmysqlstoreresult()はMySQLのC API関数です。この二つのC API関数の違いは、結果集をMySQL ServerからClient端まで全部読みました。前者は結果集の元情報を読み取りました。PHPに戻り、mysqlを使います。unbuffered_query()は、メモリの即時占有を避けることができます。遍歴中に結果に対してPHPキャッシュを行わないと、全体の実行過程は10万本または100万本以上のデータを操作しましたが、PHPが占有するメモリは常に非常に小さいです。