2011-09-06 10 views
19

Şu anda çok büyük bir CSV dosyası için bir içe aktarma komut dosyası yazıyorum. Sorun, zaman aşımı nedeniyle bir süre sonra durması veya bir bellek hatası vermesidir.Zaman aşımı ve bellek hatası olmadan çok büyük csv dosyası işleme

Fikrim şimdi "100 satır" adımlarında CSV dosyasını ayrıştırmak ve 100 satır sonra komut dosyasını otomatik olarak çağırmak oldu. Bunu başlıkla (konum ...) elde etmeye çalıştım ve şu anki çizgiyi aldım ama istediğim gibi çalışmadı.

Bunun için daha iyi bir yol var mı, yoksa birisinin bellek hatası ve zaman aşımından nasıl kurtulacağı hakkında bir fikri var mı?

+2

ne kadar büyük CSV dosyası nedir? Bunu bir veritabanında almanız mı gerekiyor? –

+0

cevabımı da bazı karşılaştırmaları da içeren http://stackoverflow.com/a/22744300/2037323 adresinde bulabilirsiniz. –

cevap

44

120 MB'lik bir csv akışını akıcı şekilde okumak için fgetcsv kullanıyorum (doğru İngilizce?). Bu satır doğrultusunda okur ve sonra her satırı bir veritabanına ekledim. Bu şekilde, her yinelemede yalnızca bir satır bellekte tutulur. Script hala 20 dk. koşmak. Belki bir dahaki sefere Python'u deneyebilirim… Bir diziye çok büyük bir csv dosyası yüklemeye çalışmayın, bu gerçekten çok fazla bellek tüketir.

// WDI_GDF_Data.csv (120.4MB) are the World Bank collection of development indicators: 
// http://data.worldbank.org/data-catalog/world-development-indicators 
if(($handle = fopen('WDI_GDF_Data.csv', 'r')) !== false) 
{ 
    // get the first row, which contains the column-titles (if necessary) 
    $header = fgetcsv($handle); 

    // loop through the file line-by-line 
    while(($data = fgetcsv($handle)) !== false) 
    { 
     // resort/rewrite data and insert into DB here 
     // try to use conditions sparingly here, as those will cause slow-performance 

     // I don't know if this is really necessary, but it couldn't harm; 
     // see also: http://php.net/manual/en/features.gc.php 
     unset($data); 
    } 
    fclose($handle); 
} 
12

Ne kadar zaman harcayacağı ve ne kadar bellek gerektiğini umursamıyorsanız, bu komut dosyasının değerlerini kolayca artırabilirsiniz. Sadece senaryonun üstüne aşağıdaki satırları ekleyin:

ini_set('memory_limit', '512M'); 
ini_set('max_execution_time', '180'); 

yapmak, komut memory_limit için iyi bir değer bulmak gerekiyor ne kadar bellek öğrenebilirsiniz memory_get_usage() fonksiyonu ile.

Ayrıca, bir dosya satırını okumanızı sağlayan fgets()'a da bakmak isteyebilirsiniz. Bunun daha az bellek aldığından emin değilim, ama bunun gerçekten işe yarayacağını düşünüyorum. Ancak bu durumda bile max_execution_time değerini daha yüksek bir değere yükseltmelisiniz.

+1

Bu, elbette dosyanın her zaman aynı boyutta olduğunu biliyorsanız, sadece iyi bir yaklaşımdır. –

+3

Eğer bir spermik boyuttan daha büyük olmadığını biliyorsanız, aynı zamanda çalışır. – 2ndkauboy

-2

Oh. Sadece bu script'i aptal web arayüzü üzerinden değil CLI olarak adlandırın. Yani, yürütme süresi sınırı etkilemez.
Ve her zaman çözümlenmiş sonuçları tutmaya devam etmeyin, ancak hemen aşağı yazın - bu nedenle, bellek sınırından etkilenmeyeceksiniz.

12

ben dosya yükleyerek ve mysql en LOAD DATA hızlı çözüm örn YEREL sorgu kullanarak ekleme bulabilirsiniz:

$sql = "LOAD DATA LOCAL INFILE '/path/to/file.csv' 
     REPLACE INTO TABLE table_name FIELDS TERMINATED BY ',' 
     ENCLOSED BY '\"' LINES TERMINATED BY '\r\n' IGNORE 1 LINES"; 
    $result = $mysqli->query($sql); 
+0

Wow 5 dakikadan + gittim, daha sonra 5 saniyeden kısa bir süre için 64000 kayıt csv aldım. Bu fantastik! – Iznogood