17

次のような非常に単純なクエリがあります。

$result = $pdo->query('SELECT * FROM my_table');

foreach($result as $r) {
    // do some stuff
}

しかし、これを実行すると、次のエラーが発生します。

致命的なエラー: 行 15 の /path/to/myfile.php で 134217728 バイトの許容メモリ サイズが使い果たされました (32 バイトを割り当てようとしました)

「Line 15」が$pdo->queryラインです。

die()クエリの後に置くと、同じエラーが発生します。

これは一度に 1 行しか取得できないと思っていました。なぜそんなに多くのメモリを使用しているのですか?

4

1 に答える 1

38

クエリを呼び出す前のメモリ使用量は 635384 バイトです。クエリは、レコードごとにチャンクで割り当てられると思います。

ディンディンディン!

MySQL に接続するとき、PHP はバッファリングされたクエリの使用を好みます。これは、接続に使用している方法に関係なく当てはまります。バッファリングされたクエリを使用すると、要求時にフェッチされるのではなく、結果セット全体がすぐにフェッチされます。これは通常、往復が少ないため、パフォーマンスに適しています。

しかし、PHP のすべてと同様に、落とし穴があります。バッファリングページに記載されているように:

libmysql をライブラリとして使用する場合、PHP のメモリ制限は、データが PHP 変数にフェッチされない限り、結果セットに使用されるメモリをカウントしません。mysqlnd を使用すると、計算されるメモリには完全な結果セットが含まれます。

PHP 5.3 を使用しています。これは、mysqlnd を使用している可能性が高いことを意味します。

ここでは、バッファリングされたクエリをオフにする必要があります。これは、MySQL へのすべての PHP インターフェイスで異なる方法で行われます。

  • PDO の場合、PDO::MYSQL_ATTR_USE_BUFFERED_QUERY属性をに設定する必要がありますfalse
  • mysqli の場合、MYSQLI_USE_RESULT定数をqueryメソッドに渡す必要があります。
  • mysql の場合、mysql_unbuffered_queryの代わりにを呼び出す必要がありますmysql_query

完全な詳細と例は、ページにあります。

巨大でバッファリングされていないクエリの落とし穴!

別のクエリを発行する前に、ステートメント ハンドルを適切に閉じ、結果セットを解放する必要があります。

  • PDO では、これはcloseCursorステートメント ハンドルを呼び出すことを意味します。
  • mysqli では、これは、作業内容に応じてfree_result、ステートメント ハンドルまたは結果ハンドルで呼び出すことを意味します。free
  • mysql では、これは呼び出しを意味します。mysql_free_result

これを行わないと、エラーが発生します。

于 2012-12-05T18:15:19.857 に答える