首頁 >後端開發 >php教程 >解決PHP里大量資料循環時記憶體耗盡問題的方法

解決PHP里大量資料循環時記憶體耗盡問題的方法

coldplay.xixi
coldplay.xixi轉載
2020-08-31 17:22:383647瀏覽

解決PHP里大量資料循環時記憶體耗盡問題的方法

相關學習推薦:#php程式設計(影片)

最近在開發一個PHP程式時遇到了下面的錯誤:

PHP Fatal error: Allowed memory size of 268 435 456 bytes exhausted

#錯誤訊息顯示允許的最大記憶體已經耗盡。遇到這樣的錯誤起初讓我很詔異,但轉眼一想,也不奇怪,因為我正在開發的這個程式是要用一個foreach循環語句在一個有4萬條記錄的表裡全表搜尋具有特定特徵的數據,也就是說,一次要把4萬個數據取出,然後逐條檢查每天數據。可想而知,4萬個資料全部載入到記憶體中,記憶體不爆才怪。

畢竟程式設計這麼多年,我隱約記得PHP裡提供有非一次全部載入資料的API,是像處理串流媒體那樣,隨用隨取隨丟、資料並不會累積在記憶體的查詢方法。經過簡單的搜索,果然在官方網站上找到的正確的用法。

這個問題在PHP的官方網站上叫緩衝查詢和非緩衝查詢(Buffered and Unbuffered queries)。 PHP的查詢缺省模式是緩衝模式。也就是說,查詢資料結果會一次全部提取到記憶體裡供PHP程式處理。這樣給了PHP程式額外的功能,比如說,計算行數,將指標指向某一行等。更重要的是程式可以對資料集反覆進行二次查詢和過濾等操作。但這種緩衝查詢模式的缺陷就是消耗內存,也就是用空間換速度。

相對的,另外一種PHP查詢模式是非緩衝查詢,資料庫伺服器會一條一條的返回數據,而不是一次全部返回,這樣的結果就是PHP程式消耗較少的內存,但卻增加了資料庫伺服器的壓力,因為資料庫會一直等待PHP來取數據,一直到資料全部取完。

很顯然,緩衝查詢模式適用於小資料量查詢,而非緩衝查詢適應於大資料量查詢。

對於PHP的緩衝模式查詢大家都知道,以下列舉的範例是如何執行非緩衝查詢API。

非緩衝查詢方法一: 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();
?>

非緩衝查詢方法二: 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;
   }
}
?>

非緩衝查詢方法三: 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中文網網友小陳給了一個正確的方式

<?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中文網php圖文教學頻道,原作者: 戰神悟空 ,php中文網二次編輯。

以上是解決PHP里大量資料循環時記憶體耗盡問題的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:webhek.com。如有侵權,請聯絡admin@php.cn刪除

相關文章

看更多