PHPからMySQLのクエリ送信のバッファリングについて
PHP-users 32941を見て、クエリ結果のバッファリングってどうなってるんだろうと思ったので調べてみた。詳細は以下によるが、何も考えずデフォルトでクエリ結果を取得する限りはバッファリングあり、つまりクエリ結果をPHPが一括で読み込んでいる。
なお、ここで言っているバッファリングありとは、MySQLがAPIレベルで行っているものである。従って、次のようなPHPスクリプトを書いたからといって、バッファリングなし。とはならない。(以下のように書いてもバッファリングありです)
$result = mysql_query($sql) while ($row = mysql_fetch_array($result)) { ; }
クエリの戻りが大きいSQLのときは、バッファリングなしでやってみるとよい結果がでるかもしれない。もっとも、バッファリングなしでは、PHPの負担は減るが、MySQLサーバ側に負担がかかるっぽいので、単純に置換すればよいというものでもなさげ。
PHPからMySQLを使う手段は、mysql、mysqli、PDO の3種類。これらについて調べる。
まず、一番低レベルなMySQLのネイティブAPIレベルでは、次のようにバッファありなしの2種類の関数がある。
- MySQL API : mysql_store_result()
- http://dev.mysql.com/doc/refman/4.1/ja/mysql-store-result.html
- クエリの結果セット全体をクライアントに読み込む
- MySQL API : mysql_use_result()
- http://dev.mysql.com/doc/refman/4.1/ja/mysql-store-result.html
- クエリの結果セットを1行ずつ個別に取得する
mysqli の場合、
- PHP : mysqli->query()
- バッファありなしは、第2パラメータ$resultmodeで指定
- http://jp.php.net/manual/ja/function.mysqli-query.php
PDO の場合、
-
- バッファありなしは、PDO::MYSQL_ATTR_USE_BUFFERED_QUERY で指定
- ただし、これを使うとMySQLに依存するので fetchAll() 使用を推奨
- http://jp.php.net/manual/ja/ref.pdo-mysql.php
PHPのソースから、mysql_use_result とmysql_store_result を抽出
php-5.2.4\README.STREAMS(325): state->result = mysql_use_result(&state->conn); php-5.2.4\ext\mysql\php_mysql.c(112): #define MYSQL_USE_RESULT 0 php-5.2.4\ext\mysql\php_mysql.c(113): #define MYSQL_STORE_RESULT 1 php-5.2.4\ext\mysql\php_mysql.c(1306): mysql_result = mysql_use_result(&mysql->conn); php-5.2.4\ext\mysql\php_mysql.c(1341): if(use_store == MYSQL_USE_RESULT) { php-5.2.4\ext\mysql\php_mysql.c(1342): mysql_result=mysql_use_result(&mysql->conn); php-5.2.4\ext\mysql\php_mysql.c(1344): mysql_result=mysql_store_result(&mysql->conn); php-5.2.4\ext\mysql\php_mysql.c(1356): if (use_store == MYSQL_USE_RESULT) { php-5.2.4\ext\mysql\php_mysql.c(1395): php_mysql_do_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQL_STORE_RESULT); php-5.2.4\ext\mysql\php_mysql.c(1404): php_mysql_do_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQL_USE_RESULT); php-5.2.4\ext\mysql\php_mysql.c(1439): php_mysql_do_query_general(query, mysql_link, id, db, MYSQL_STORE_RESULT, return_value TSRMLS_CC); php-5.2.4\ext\mysqli\mysqli.c(823): result = (resmode == MYSQLI_STORE_RESULT) ? mysql_store_result(mysql->mysql) : php-5.2.4\ext\mysqli\mysqli.c(824): mysql_use_result(mysql->mysql); php-5.2.4\ext\mysqli\mysqli_api.c(498): php_error_docref(NULL TSRMLS_CC, E_WARNING, "Function cannot be used with MYSQL_USE_RESULT"); php-5.2.4\ext\mysqli\mysqli_api.c(1268): php_error_docref(NULL TSRMLS_CC, E_WARNING, "Function cannot be used with MYSQL_USE_RESULT"); php-5.2.4\ext\mysqli\mysqli_api.c(2048): if (!(result = mysql_store_result(mysql->mysql))) { php-5.2.4\ext\mysqli\mysqli_api.c(2102): if (!(result = mysql_use_result(mysql->mysql))) { php-5.2.4\ext\mysqli\mysqli_nonapi.c(249): result = (resultmode == MYSQLI_USE_RESULT) ? mysql_use_result(mysql->mysql) : mysql_store_result(mysql->mysql); php-5.2.4\ext\mysqli\mysqli_warning.c(74): result = mysql_store_result(mysql); php-5.2.4\ext\pdo_mysql\mysql_statement.c(78): res = mysql_store_result(S->H->server); php-5.2.4\ext\pdo_mysql\mysql_statement.c(225): S->result = mysql_use_result(H->server); php-5.2.4\ext\pdo_mysql\mysql_statement.c(227): S->result = mysql_store_result(H->server); php-5.2.4\ext\pdo_mysql\mysql_statement.c(277): S->result = mysql_use_result(H->server); php-5.2.4\ext\pdo_mysql\mysql_statement.c(280): S->result = mysql_store_result(H->server); php-5.2.4\ext\pdo_mysql\mysql_statement.c(624): res = mysql_store_result(S->H->server); php-5.2.4\ext\sybase\php_sybase_db.c(810): /* The following is more or less the equivalent of mysql_store_result(). php-5.2.4\ext\sybase_ct\php_sybase_ct.c(1235): /* The following (if unbuffered) is more or less the equivalent of mysql_store_result().