この記事では主に、PHP で MySQL にクエリを実行して原理、マニュアル、ソース コード分析から多数の結果を返すときのメモリ使用量の問題について説明します。また、MySQL C API の使用についても説明します。
昨日、同僚が PHP ディスカッション グループ (276167802 検証: csl、興味があれば参加して一緒に議論できます) で、彼が取り組んでいたプロジェクトが多すぎる結果 (最大 100,000) を返したと述べました。 MySQL クエリの結果、PHP メモリが不足しました。そこで、返された MySQL の結果を反復処理する前に、データがすでにメモリ内にあるのではないかと彼は尋ねました。
[php]
while ($row = mysql_fetch_assoc($result)) {
// ...
}
もちろん、この問題には多くの最適化方法がありますが、この問題に関する限り、私が最初に思いつくのは、MySQL が古典的な C/S (クライアント/サーバー、クライアント/サーバー) モデルであるということです。結果セットを走査する前に、基盤となる実装がネットワーク経由ですべてのデータをクライアントのバッファに読み取っている可能性があります (TCP/IP が使用されていると仮定します)。別の可能性としては、データがまだサーバー側の送信バッファ内にある可能性があります。クライアントに渡されていません。
PHP と MySQL のソース コードを見る前に、PHP マニュアルに同様の機能を持つ 2 つの関数があることに気付きました。
[php]
mysql_query()
mysql_unbuffered_query()
2 つの関数の文字通りの意味と説明により、前者の関数が実行されると、すべての結果セットがサーバーからクライアントのバッファーに読み取られますが、後者の関数は読み取られません。 unbuffered(アンバッファード)」という意味です。
つまり、mysql_unbuffered_query() を使用して大きな結果セットを返す SQL ステートメントを実行する場合、結果を走査する前に PHP のメモリが結果セットによって占有されることはありません。また、mysql_query() を使用して結果セットを実行する場合も同様です。同じステートメントでも、関数が返されると、PHP のメモリ使用量が急激に増加し、すぐにすべてのメモリが消費されます。
PHP の関連コードを読むと、これら 2 つの関数の実装の類似点と相違点がわかります。
[php]
/* {{{ proto resource mysql_query(string query [, int link_identifier])
SQL クエリを 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])
結果行のフェッチやバッファリングを行わずに、SQL クエリを MySQL に送信します */
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() の実装を見てみましょう。
[php]
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 関数です。これら 2 つの C API 関数の違いは、後者は結果セット全体を MySQL サーバーからクライアントに読み取るのに対し、前者は結果セットのみを読み取ることです。メタ情報。
PHP に戻り、mysql_unbuffered_query() を使用して、即時のメモリ占有を回避します。結果がトラバーサル プロセス中に「PHP キャッシュ」されない場合 (配列に配置する場合など)、実行プロセス全体が 100 個で動作します。数千項目、または数百万以上のデータがありますが、PHP が占有するメモリは常に非常に小さいです。
この記事が大多数の PHP 開発者にとって役立つことを願っています。この記事を読んでいただきありがとうございます。