2011-08-31 28 views
12

Tôi đã sử dụng để lấy lượng lớn dữ liệu bằng cách sử dụng mysql_query rồi lặp lại từng kết quả một để xử lý dữ liệu. Ví dụ:Trong PHP, những gì xảy ra trong bộ nhớ khi chúng ta sử dụng mysql_query

$mysql_result = mysql_query("select * from user"); 
while($row = mysql_fetch_array($mysql_result)){ 
    echo $row['email'] . "\n"; 
} 

Gần đây tôi nhìn vào một vài khuôn khổ và nhận ra rằng họ lấy tất cả dữ liệu vào một mảng trong bộ nhớ và trở về mảng.

$large_array = $db->fetchAll("select * from user"); 
foreach($large_array as $user){ 
    echo $user['email'] . "\n"; 
} 

Tôi muốn biết ưu/nhược điểm của từng phương pháp. Nó xuất hiện với tôi rằng tải tất cả mọi thứ trong bộ nhớ là một công thức cho thảm họa nếu bạn có một danh sách rất dài các mặt hàng. Nhưng sau đó một lần nữa, một đồng nghiệp nói với tôi rằng trình điều khiển mysql sẽ phải đặt kết quả đặt trong bộ nhớ anyway. Tôi muốn nhận được ý kiến ​​của một người hiểu rằng câu hỏi là về hiệu suất. Xin vui lòng không bình luận về mã, tôi chỉ làm cho nó lên như một ví dụ cho bài viết.

Cảm ơn

+0

Tại sao bạn không thử chúng? –

+2

Ngược lại, hãy xem tại http://www.php.net/manual/en/function.mysql-unbuffered-query.php. – deceze

Trả lời

1

Đúng là thư viện MySQL "bình thường" tìm nạp tất cả dữ liệu trong bộ nhớ máy khách.Nó thường làm như vậy bằng cách sử dụng mysql_store_result(). Bạn có thể chia nhỏ các truy vấn quá lớn như được hiển thị ở trên với từ khóa LIMIT, nhưng có nguy cơ dữ liệu không nhất quán vì chúng có thể thay đổi ở giữa. Bạn có thể quan tâm đến việc này bằng cách sử dụng khóa.

Cách tiếp cận khác có thể là sử dụng mysql_use_result(), sử dụng nhiều tài nguyên hơn ở phía máy chủ và yêu cầu hoàn thành công việc tìm nạp ASAP.

+0

Ein Liên kết zur Englischen MySQL Dokumentation wäre glaube ich angebrachter. : o) – deceze

+0

Oups, xin lỗi, kích thích. Tôi đã thay đổi nó ngay bây giờ để tất cả các bạn có thể hưởng lợi từ nó :-) – glglgl

+0

Thay đổi dữ liệu ở giữa = VERY điểm tốt! – U0001

-2

Chỉ cần một cái gì đó tôi học được khi nói đến hiệu suất: foreach là nhanh hơn so với một vòng lặp while. Có lẽ bạn nên điểm chuẩn kết quả của mỗi người và xem kết quả nào nhanh hơn và ít tốn kém bộ nhớ hơn. IMHO, tôi thích cách tiếp cận thứ hai tốt hơn. Nhưng bạn có thực sự cần mỗi cột đơn trong bảng người dùng không? Nếu không, chỉ cần xác định các cột mà bạn cần thay vì sử dụng * để lấy tất cả. Vì điều này cũng sẽ giúp với bộ nhớ và tốc độ là tốt.

+4

OMG foreach nhanh hơn một chút –

+0

có, khi xử lý các mảng dữ liệu lớn, hãy sử dụng 'foreach' khi có thể thay vì các vòng lặp' while'. http://juliusbeckmann.de/blog/php-foreach-vs-while-vs-for-the-loop-battle.html điều này đã được chứng minh thời gian và thời gian một lần nữa ... – SoLoGHoST

+3

câu hỏi không phải là về foreach vs trong khi. Và loại so sánh này là vô ích: bạn thực hiện truy vấn sql 12 giây nhưng bạn đang cố gắng tối ưu hóa vòng lặp 0,1 giây ... –

4

bạn đang trộn các vấn đề.

  • khả năng sử dụng, mà làm cho WAY mã của bạn mượt mà hơn với mảng
  • và thuật toán được tối ưu hóa, khi lập trình viên chưa từng trải có xu hướng tải TẤT CẢ dữ liệu vào kịch bản thay vì làm cơ sở dữ liệu để làm tất cả các tính toán hoặc nhận được dữ liệu trong các phần.

So. Khung không tìm nạp tất cả dữ liệu. Họ lấy chỉ là những gì lập trình viên đã viết.
Vì vậy, một lập trình viên giỏi sẽ không tìm nạp lượng lớn dữ liệu vào mảng. Trong vài trường hợp này khi nó thực sự cần thiết, người ta sẽ sử dụng tìm nạp theo từng dòng cũ (và mọi khung công tác đều cung cấp một phương thức cho việc này). Trong tất cả các trường hợp khác, việc lấy mẫu sẵn sàng trong mảng mịn sẽ được sử dụng.

Cũng xin lưu ý rằng các khuôn khổ sẽ không bao giờ làm những việc như dữ liệu lặp lại ngay bên trong vòng lặp cơ sở dữ liệu.
Mọi khuôn khổ tốt sẽ sử dụng một mẫu để xuất nội dung và trong trường hợp này, một mảng cực kỳ tiện dụng.

+0

Cảm ơn Đại tá Shrapnel. Re: echoing, đó chỉ là một ví dụ để minh họa. – U0001

2

Khi làm việc với bộ kết quả lớn, tôi thường đi qua lô, như thế này:

$current = 0; 
$batchSize = 1000; 

while (true) { 
    $large_array = $db->fetchAll(sprintf("select * from user limit %s, %s", $current, $batchSize)); 
    if (sizeof($large_array) == 0) { 
    break; 
    } 

    $current += sizeof($large_array); 
    foreach($large_array as $user){ 
    echo $user['email'] . "\n"; 
    } 
} 

Chừng nào mã của bạn không bị rò rỉ bộ nhớ, bạn sẽ không phải lo lắng về phương pháp sử dụng nhiều ký ức. Về mặt hiệu suất, việc tải toàn bộ kết quả được đặt trong một truy vấn có thể nhanh hơn, mặc dù bạn có khả năng sẽ đạt đến giới hạn bộ nhớ rất sớm theo cách này, vì vậy hiệu suất không thực sự là vấn đề của bạn nữa.

Nhân tiện, việc thử nghiệm bản thân tương đối dễ dàng, bằng cách thiết lập một tập lệnh đo thời gian (và bộ nhớ đỉnh) của cả hai đoạn mã. Tôi cá rằng chúng sẽ không khác nhiều về thời gian.

+0

tại sao không tạo vòng lặp trong một thời gian? –

+0

Có, tôi có thể tự kiểm tra nhưng tôi lười. Và tôi thậm chí còn tò mò hơn về ý kiến ​​chuyên gia về nó. Ví dụ, một số người ở đây đã trình bày các cách tiếp cận khác nhau và giải thích chúng. Điều này, với tôi, là tốt hơn so với một thử nghiệm. – U0001

Các vấn đề liên quan