2012-02-11 42 views
5

Tôi đang viết tập lệnh theo lô và nhận được lỗi Allowed memory size of 134217728 bytes exhausted.Tại sao "Kích thước bộ nhớ được phép cạn kiệt"?

Tôi không hiểu tại sao bộ nhớ được lấp đầy. Tôi đã thử xóa biến số $row, nhưng điều đó không thay đổi gì cả. Đây là mã của tôi:

// ... (sql connection) 
$result = mysql_query("SELECT * FROM large_table"); 

while ($row = mysql_fetch_array($result)) { 
    echo $row['id'] . PHP_EOL; 
    unset($row); 
} 

(đơn giản hóa code)

Tại sao bộ nhớ lấp đầy, và làm thế nào tôi có thể tránh nó?

Lưu ý: đây là tập lệnh theo lô. Điều này là bình thường mà tôi phải xử lý dữ liệu như vậy (đi qua 1 triệu dòng).

Cập nhật: Việc hết bộ nhớ xảy ra xung quanh dòng 400 000, vì vậy điều này phải là thứ gì đó trong vòng lặp? Tôi muốn tránh phải thực hiện phân trang nếu có thể.

+0

Nó không giống như bạn nên chạy ra khỏi bộ nhớ từ đoạn mã đó. Có một số biến khác đang phát triển mỗi lần lặp? –

+0

sẽ không truy vấn mysql thực sự trả về toàn bộ bảng -> có nghĩa là kết quả sẽ được tính vào bộ nhớ đã sử dụng? – KillerX

+0

Có thể là một gợi ý ngớ ngẩn, nhưng đó là điều duy nhất tôi có thể nghĩ đến: có lẽ bạn có thể thử xả bộ đệm đầu ra của mình? – Martijn

Trả lời

10

Hãy thử sử dụng http://www.php.net/manual/en/function.mysql-unbuffered-query.php (mysql_unbuffered_query()) để ngăn chặn toàn bộ bảng được nạp vào bộ nhớ, nhưng vẫn tránh pagination.

+0

Điều đó đã làm được! Trực giác của bạn là đúng, và tôi thích nó nó trả lời gốc của vấn đề. –

+0

btw Tôi không hiểu các downvotes mà không có giải thích ... Tôi upvoted để bù đắp –

+0

Tôi không chắc chắn đây là cách tiếp cận đúng, nhưng 1 vì nó trả lời câu hỏi ban đầu :) – halfer

4

Giới hạn truy vấn của bạn để có kết quả ví dụ 1k và thực thi lại (với trường hợp bù trừ) cho đến khi bạn trải qua tất cả bảng. Việc bỏ đặt chỗ hiện tại của bạn không có sự khác biệt, vì hàng $ bị ghi đè với mỗi lần lặp lại, do đó bạn có thể bỏ qua nó.

$chunk_size = 1000; 
$done = 0; 

$keep_asking_for_data = true; 
do{ 
    $result = mysql_query("SELECT * FROM `large_table` LIMIT {$done}, {$chunk_size}"); 
    $num_rows = mysql_num_rows($result); 
    if($num_rows){ 
     $done += $num_rows; 
     while($row = mysql_fetch_assoc($result)){ 
      echo "{$row['id']}\n"; 
     } 
    } else { 
     $keep_asking_for_data = false; 
    } 
    mysql_free_result($result); 
}while($keep_asking_for_data); 

Chỉ cần biên soạn trên đầu tôi, hy vọng nó hoạt động = D

+0

Tôi đã cố gắng thêm bỏ đặt giá trị để buộc bộ sưu tập bộ nhớ được sử dụng bởi biến này, không được đảm bảo khác (PHP GC). Dù sao, hãy xem nhận xét cho câu trả lời khác và cập nhật câu hỏi –

+0

Chết tiệt! "Tôi muốn tránh phải thực hiện phân trang nếu có thể." Điều này không có ở đó khi tôi tạo mã: D – PalmTree

+0

+1 có vẻ tốt với tôi! – halfer

1

Nếu bạn đang sử dụng MySQL, trang kết quả của bạn, do đó bạn không làm chấm dứt bộ nhớ có sẵn của bạn. MySQL chính nó đang chiếm bộ nhớ này với resultset cơ sở dữ liệu của bạn. Có một cái nhìn tại liên kết sau, đặc biệt là cú pháp LIMIT offset, limit của SELECT:

http://dev.mysql.com/doc/refman/5.0/en/select.html

+0

Đó là một ý tưởng nhưng tôi thú nhận rằng tôi quá lười biếng để làm điều đó: p. Dù sao, lỗi xảy ra xung quanh dòng 400 000 (xem câu hỏi cập nhật) để nó có thể là một cái gì đó trong vòng lặp mà có lẽ tôi có thể sửa chữa? –

+0

Cách tiếp cận của bạn khi nó đứng * nên * để đệm một số kết quả - loại bỏ bộ đệm để phân trang trở nên không cần thiết có lẽ không phải là cách để làm điều đó, imo. Dù sao thì nó cũng dễ dàng bây giờ - @PalmTree đã làm điều đó cho bạn :) – halfer

+0

Tại sao bạn nghĩ việc xóa phân trang không phải là cách tốt để làm điều đó? –

1

Tôi đã gặp sự cố tương tự với cơ sở dữ liệu lớn. Tôi đã hết bộ nhớ, mặc dù chưa đặt biến $ row vào khoảng 400.000 bản ghi, nhưng truy vấn không được lọc đã sửa nó.

Chỉ cần để tham khảo cho những người khác (và tôi khi tôi làm điều đó một lần nữa!), Một số không có bộ đệm dụ truy vấn code is:

$sql = "SELECT SEQ, RECTYPE, ROSTERGRP, EMPNM, EMPNUM, DT, RDUTYCAT, ADUTYCAT FROM " . 
     $tblRosters . " ORDER BY EMPNUM,DT"; 
$result = mysql_unbuffered_query($sql, $dbConn); 
$svRow = array(); 
while ($row = mysql_fetch_array($result)) 
    { 
     // your processing code here 
    } 
    // Unset, close db etc. if you are finished goes here. 
Các vấn đề liên quan