Büyük bir tablo yineleme ve bir site haritası oluşturmak için CakePHP tavsiye?

6 Cevap php

Ben şu anda 50.000 'den fazla kayıt, site haritası bir URI için her kayıt eşit olan bir tablo, CakePHP kullanarak bir XML site haritası oluşturmak için çalışıyorum. Şimdi ben bakan değilim sorun bunu üretirken CakePHP iki nedenden dolayı, bellek beni çalıştıran olduğunu:

  1. A find('all') 50,000 URI'lerinin kümesinin tamamını büyük bir ilişkisel dizi inşa ediyor.
  2. Ben denetleyicisi kendisinden çıkış HTML istemiyorum, çünkü ben bir $this->set() çağrısıyla görünümüne, vb URI, öncelik, değişim sıklığını içeren ilişkisel dizi transfer ediyorum - yine büyük olan , 50,000 endeksleri ihtiva etmektedir.

Bu MVC ve CakePHP yönergeleri izleyerek bu süre yapmak için, tüm olası mı?

6 Cevap

Eğer 50.000 kayıtları üzerinde bellek çalıştırmak zorunda emin misiniz? Bir satır boyutu (oldukça büyük) 1K olsa bile, veri ~ 50 MB ile uğraşmak zorunda kalacak? Benim P1 o işlemek için yeterli RAM vardı. Varsayılan daha yüksek php.ini içinde memory_limit ayarlayın. (Ayrıca max_execution_time verdiği düşünün.)

On the other hand, if you consider the data set as too huge and processing it as too resource intensive, you should not serve that page dynamically, it is the perfect DDoS bait. (At least I would cache it heavily.) You could schedule a cron job to re-generate the page every X hours by a server side script free from the MVC penalty of serving all data at once to the view, it could work on the rows sequentially.

Bu soru eski olduğunu biliyorum, ama gerçekten çok büyük sorguları için bence iyi bir çözüm hala var.

Büyük bir resultset yineleme aracılığıyla size DboSource yöntemleri kullanabilirsiniz.

İlk DBO olsun

$dbo = $this->Model->getDataSource();

Sorgu oluşturmak

$sql = $dbo->buildStatement($options);

Sonra deyimini yürütmek ve sonuçları ile yineleme

if ($dbo->execute($sql))
{
    while ($dbo->hasResult() && $row = $dbo->fetchResult()) {
        // $row is an array with same structure like find('first')
    }
}

Ben bu hafta benzer bir sorun vardı, ve Containable Davranış tökezledi. Bu, herhangi bir ilişki ilgili sorguları (Eğer varsa) kesmek için izin verir.

En iyi çözüm programlı bir anda kayıt küçük parçalar üzerinden LIMIT and OFFSET, ve döngü kullanmak olacaktır. Bu seferde belleğe 50K kayıtları doldurma sizi kurtarır.

bellek tükendi istemiyorsanız ('all') bulmak yol çok hırslı olduğunu, daha spesifik olmak gerekir.

Yukarıda belirtildiği gibi, Containable davranışı kullanın. Yalnızca (ilişkili tablolar olmadan) ve alanları sadece bir çift için sofranızdan sonuçları, gerekiyorsa, bu gibi daha açık bir sorgu daha iyi olmalı:

$results = $this->YourModel->find('all', array(
    'contain' => false,
    'fields' => array('YourModel.name', 'YourModel.url')
);

Ayrıca bir html önbellek mekanizması (cakePHP bir yerleşik veya bir suggested by Matt Curry kullanarak vardır) eklemeyi düşünmelisiniz.

Tabii ki önbelleğe alınmış bir sürümü olacak ve mükemmel güncel listenize olmayacaktır. Eğer daha fazla kontrol sahibi olmak istiyorsanız her zaman önbelleğe değerini güncellemek ve buradan önbelleğe xml dosyasını yeniden için model afterSave / afterDelete geri çağrıları kullanarak, (kullanarak Cache::write) kek önbellek sonucu kaydedebilirsiniz.

Kullan https://github.com/jamiemill/cakephp_find_batch ya da kendiniz bu mantığı uygulamak.

(Eğer ilişkiler varsa) unBindModel denedim ...

Ben CakePHP'de büyük sorguları yapmak zorunda zaman ben sadece çok daha hızlı mysql_query gibi "normal" mysql-fonksiyonları, mysql_fetch_array vb kullanabilirsiniz, ve bellek hiçbir eksikliği ...