MySQL sorgu sonuçlarını işlerken nasıl PHP bellek kullanımını sınırlamak mı?

4 Cevap php

Yani kullanıcıların kayıtları bir bütün demet ne olabilir için CSV indirmenize olanak sağlayan bir PHP sayfası var. Sorun daha fazla bellek kullandığı, MySQL sorgu döndürür daha fazla sonuç olduğunu. Bu gerçekten şaşırtıcı değil, ama bu bir sorun teşkil etmez.

Ben mysql_unbuffered_query kullanarak çalıştı () ama herhangi bir fark yoktu, bu yüzden ben daha önce işlenen satırlar ne varsayalım tarafından kullanılan bellek boşaltmak için başka bir yol gerekir. Bunu yapmak için standart bir yol var mı?

İşte ben neden bahsettiğimi gösteren yorumladı günlüğü bulunuyor:

// Method first called
2009-10-07 17:44:33 -04:00 --- info: used 3555064 bytes of memory

// Right before the query is executed
2009-10-07 17:44:33 -04:00 --- info: used 3556224 bytes of memory

// Immediately after query execution
2009-10-07 17:44:34 -04:00 --- info: used 3557336 bytes of memory

// Now we're processing the result set
2009-10-07 17:44:34 -04:00 --- info: Downloaded 1000 rows and used 3695664 bytes of memory
2009-10-07 17:44:35 -04:00 --- info: Downloaded 2000 rows and used 3870696 bytes of memory
2009-10-07 17:44:36 -04:00 --- info: Downloaded 3000 rows and used 4055784 bytes of memory
2009-10-07 17:44:37 -04:00 --- info: Downloaded 4000 rows and used 4251232 bytes of memory
2009-10-07 17:44:38 -04:00 --- info: Downloaded 5000 rows and used 4436544 bytes of memory
2009-10-07 17:44:39 -04:00 --- info: Downloaded 6000 rows and used 4621776 bytes of memory
2009-10-07 17:44:39 -04:00 --- info: Downloaded 7000 rows and used 4817192 bytes of memory
2009-10-07 17:44:40 -04:00 --- info: Downloaded 8000 rows and used 5012568 bytes of memory
2009-10-07 17:44:41 -04:00 --- info: Downloaded 9000 rows and used 5197872 bytes of memory
2009-10-07 17:44:42 -04:00 --- info: Downloaded 10000 rows and used 5393344 bytes of memory
2009-10-07 17:44:43 -04:00 --- info: Downloaded 11000 rows and used 5588736 bytes of memory
2009-10-07 17:44:43 -04:00 --- info: Downloaded 12000 rows and used 5753560 bytes of memory
2009-10-07 17:44:44 -04:00 --- info: Downloaded 13000 rows and used 5918304 bytes of memory
2009-10-07 17:44:45 -04:00 --- info: Downloaded 14000 rows and used 6103488 bytes of memory
2009-10-07 17:44:46 -04:00 --- info: Downloaded 15000 rows and used 6268256 bytes of memory
2009-10-07 17:44:46 -04:00 --- info: Downloaded 16000 rows and used 6443152 bytes of memory
2009-10-07 17:44:47 -04:00 --- info: used 6597552 bytes of memory

// This is after unsetting the variable. Didn't make a difference because garbage
// collection had not run
2009-10-07 17:44:47 -04:00 --- info: used 6598152 bytes of memory

Ben bu (hatta daha büyük) gibi büyük sonuç kümeleri ile ilgili standart teknik çeşit var umuyorum, ama benim araştırma bir şey geldi değil.

Fikirler?

İşte bazı kod isteği, var:

    $results = mysql_query($query);

    Kohana::log('info', "used " . memory_get_usage() . " bytes of memory");                

    $first = TRUE;
    $row_count = 0;

    while ($row = mysql_fetch_assoc($results)) {
        $row_count++;
        $new_row = $row;

        if (array_key_exists('user_id', $new_row)) {
            unset($new_row['user_id']);
        }

        if ($first) {
            $columns = array_keys($new_row);
            $columns = array_map(array('columns', "title"), $columns);
            echo implode(",", array_map(array('Reports_Controller', "_quotify"), $columns));
            echo "\n";
            $first = FALSE;
        }

        if (($row_count % 1000) == 0) {
            Kohana::log('info', "Downloaded $row_count rows and used " . memory_get_usage() . " bytes of memory");                
        }

        echo implode(",", array_map(array('Reports_Controller', "_quotify"), $new_row));
        echo "\n";
    }

4 Cevap

Bazıları daha da profil sorunu yerde bir bellek sızıntısı olduğunu ortaya koymaktadır. Ben en basit kodu forma soyunmuş ve bellek kullanımı her yineleme ile büyümek değil. Ben Kohana (ben kullanıyorum framework) şüpheli.

Bu bir "canlı" indirmek mi? Eğer CSV üreten yaparken o derken müşteriye bu bastırıyorlar demek? Eğer öyleyse, o zaman yapabileceğiniz bazı şeyler vardır:

  1. Çıktı tamponlama kullanmayın. Eğer daha fazla bellek kullanır, hangi (biten komut dosyası tarafından) açıkça veya örtük olarak bunu temizlemek kadar bu bellekte her şeyi kaydeder;
  2. Eğer veritabanından satırları okurken, müşteriye bunları yazmak.

Bunun dışında, biz muhtemelen bazı iskelet kodu görmek gerekir.

Aslında periyodik veri reçeteye mı? MySQL istemcisi, kendi değişkenleri ve çıkış sistemi arasında veri birden fazla kopyası var çünkü PHP'nin normal tamponlama uzun süren kod için oldukça kısır olabilir. Bir kaç yıl oldu ama ben geçen iskelet kodu böyle bir şey kullanarak hatırlamak oluyor:

ob_end_flush()
mysql_unbuffered_query()
while ($row = mysql_fetch…) {
   … do something …   

   flush(); // Push to Apache
   unset($row, … all other temporary variables …);
}

Mysql_unbuffered_query kullanarak soru için teşekkürler () PHP ve MySQL geniş bir veri kümesi ile çalışan RAM azalıyor benim sorun çözüldü.

PHP Fatal error: on line 25 tükenmiş 134217728 bayt İzin bellek boyutu (32 bayt ayırmaya çalıştı) in / içerik / apps / application_price.php