2016-12-25 46 views
1

處理所以,我一直在接觸到越來越多的現實生活中的應用,其中: SELECT * FROM table太重已經,導致到 Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 47 bytes) in優雅處理大的MySQL行由PHP

什麼我目前做的是將它們分MySQL的行成batches,設置變量$perPage,然後$_GET['page']變量傳遞到頁面,一些鏈接:process.php?page=1

我認爲這是「好」。但有時候,我們希望完全自動化。所以我設置$nextPage = (int) $_GET['page'] + 1,然後重定向頁面,然後處理這些MySQL的行 header("Location: process.php?p="$nextPage)

現在,經過迭代,這將給你一些問題:

  1. 其難以調試。如果在第3頁發出警告/通知,您將無法看到這些輸出,除非您記錄它們或查看您的php日誌。
  2. 瀏覽器不允許你重定向太多。所以,我們要麼使用命令行curl,要麼編寫另一個php腳本,它將跟蹤process.php並啓用follow-redirect。

這就是我目前如何處理這個問題,但有時候認爲我需要更多的代碼才能使其工作有點令人沮喪。 有誰知道如何處理這些更優雅?

回答

1

PHP Generators對於這種情況非常理想。

甲發生器允許編寫使用的foreach超過 迭代的一組數據,而無需建立在存儲器陣列,其可以 導致您超出存儲器限制,或需要大量代碼 的處理時間來生成。相反,您可以編寫一個發生器 函數,該函數與正常函數相同,只不過返回一次而不是返回 ,發生器可以產生儘可能多的次數,以便提供要迭代的值。

您不應該將所有數據存儲到內存,而是通過塊處理記錄。

使用yield(來自C)將允許您實現這一點。

忘掉重定向的東西,這個聲音好像應該是CLI腳本。

下面是關於如何實現它的一個例子:

function getRecords() 
{ 
    $sql = 'SELECT field1, field2 FROM table'; 
    $stmt = $this->conn->prepare($sql); 
    $stmt->execute(); 
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { 
     yield $row; 
    } 
} 

foreach ($this->getRecords() as $record) { 
    //process then release, do not store 
} 

注意:

  1. 我選擇特定字段,因爲內存是你應該小心一切顧慮,SELECT *可以不必要地使你用完了內存。
  2. fetchAll()之類的東西是行不通的,因爲它會一次獲得所有行。
  3. 在迭代foreach時,不要將數據存儲在內存中,這會破壞生成器的用途。
+0

您是專業人士。顯然,這就是所需要的! –

0

在循環中;從數據庫中獲取一段數據做你想做的事,用unset()函數釋放內存,然後獲得下一條數據。