ホームページ  >  記事  >  バックエンド開発  >  PHPで大量のデータをループするときにメモリが枯渇する問題を解決する方法

PHPで大量のデータをループするときにメモリが枯渇する問題を解決する方法

coldplay.xixi
coldplay.xixi転載
2020-08-31 17:22:383587ブラウズ

PHPで大量のデータをループするときにメモリが枯渇する問題を解決する方法

関連する学習に関する推奨事項: php プログラミング(ビデオ)

最近、PHP プログラムの開発中に次のエラーが発生しました:

PHP 致命的なエラー: 許可されたメモリ サイズ 268 435 456 バイトが使い果たされました

エラー メッセージは、最大許容メモリが使い果たされたことを示しています。最初はこのようなエラーが発生したことに驚きましたが、よく考えてみると、私が開発しているプログラムでは 40,000 件のレコードを持つテーブルで

foreach ループ ステートメントが使用されているため、それは驚くべきことではありません。特徴のあるデータの場合は、一度に4万件のデータを取り出し、毎日のデータを一つ一つ確認する必要があります。 40,000件のデータをすべてメモリにロードした場合、メモリがバーストしなくても不思議ではないと考えられます。

長年プログラミングを続けてきましたが、PHP にはデータを一度に読み込まない API が用意されていたことをなんとなく覚えています。これは、ストリーミング メディアのように使用したり失われる可能性のあるクエリ メソッドであり、データは読み込まれません。記憶に蓄積されます。簡単に検索したところ、公式Webサイトに正しい使用方法が見つかりました。

この問題は、PHP の公式 Web サイトでは「バッファー クエリ」および「バッファなしクエリ」と呼ばれています。 PHP のデフォルトのクエリ モードはバッファ モードです。つまり、クエリ データの結果は、PHP プログラムによる処理のために一度にメモリに抽出されます。これにより、PHP プログラムに行数のカウント、特定の行へのポインタの指示などの追加機能が与えられます。さらに重要なことは、プログラムがデータ セットに対して二次クエリとフィルタリング操作を繰り返し実行できることです。ただし、このバッファー クエリ モードの欠点は、メモリを消費すること、つまり、速度と引き換えにスペースを消費することです。

対照的に、別の PHP クエリ モードは、非バッファ クエリです。データベース サーバーは、一度にすべてのデータを返すのではなく、1 つずつデータを返します。その結果、PHP プログラムのメモリ消費量は減りますが、メモリの消費量は増加します。すべてのデータがフェッチされるまで、データベースは PHP によるデータのフェッチを待機するため、データベース サーバーに負荷がかかります。

明らかに、バッファー クエリ モードは少量のデータ量のクエリに適しており、非バッファー クエリは大規模なデータ量のクエリに適しています。

PHP のバッファー モード クエリについては誰もが知っていますが、次の例は、非バッファー クエリ API を実行する方法です。

非バッファ型クエリ メソッド 1: mysqli

<?php
$mysqli  = new mysqli("localhost", "my_user", "my_password", "world");
$uresult = $mysqli->query("SELECT Name FROM City", MYSQLI_USE_RESULT);

if ($uresult) {
   while ($row = $uresult->fetch_assoc()) {
       echo $row[&#39;Name&#39;] . PHP_EOL;
   }
}
$uresult->close();
?>

非バッファ型クエリ メソッド 2: pdo_mysql

<?php
$pdo = new PDO("mysql:host=localhost;dbname=world", &#39;my_user&#39;, &#39;my_pass&#39;);
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);

$uresult = $pdo->query("SELECT Name FROM City");
if ($uresult) {
   while ($row = $uresult->fetch(PDO::FETCH_ASSOC)) {
       echo $row[&#39;Name&#39;] . PHP_EOL;
   }
}
?>

非バッファ型クエリ メソッド 3: mysql

<?php
$conn = mysql_connect("localhost", "my_user", "my_pass");
$db   = mysql_select_db("world");

$uresult = mysql_unbuffered_query("SELECT Name FROM City");
if ($uresult) {
   while ($row = mysql_fetch_assoc($uresult)) {
       echo $row[&#39;Name&#39;] . PHP_EOL;
   }
}
?>

php中文网ネチズンは次のように不満を述べました:

これはジェネレーターを使用する必要があります

この書き方は直接開くことができます

これはビッグデータを処理するのは不可能 その書き方によると

PHP中国ネットユーザーXiao Chen氏が正しい方法を教えてくれました

<?php

if (!function_exists(&#39;getYieldBigData&#39;)) {
    /**
     * 使用生成器返回生成器对象
     * @param array $data
     * @return Generator
     */
    function getYieldBigData($data = [])
    {
        foreach ($data as $tmp_data) {
            yield $tmp_data;
        }
        unset($tmp_data);
    }
}


if (!function_exists(&#39;foreachBigData&#39;)) {
    /**
     * 循环大量数据使用生成器来制造值
     * @param array $data
     * @return array|false
     */
    function foreachBigData($data = [])
    {
        if (0 == count($data)) {
            return false;
        }
        $tmp = [];
        foreach (getYieldBigData($data) as $v) {
            $tmp[] = $v;
        }
        unset($v);
        return $tmp;
    }
}

//调用方法
/**
 * @var $data array
 */
$data = [];
/**
 * @var $ret array
 */
$ret = foreachBigData($data);

return $ret;

初心者でも読めるようになりましたそれ!

PHPで大量のデータをループするときにメモリが枯渇する問題を解決する方法

#上記のように、この方法では 100 万回/回に到達する可能性があります。

この記事は、php 中国語 Web サイトの

php graphictutorial チャネルからのもので、原著者: God of War Wukong (php 中国語 Web サイトの 2 番目の編集者) です。

以上がPHPで大量のデータをループするときにメモリが枯渇する問題を解決する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はwebhek.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。