Büyük düz dosyaları işlemek için php komut satırı dosyaları optimize

4 Cevap php

Ben php işlemek için gereken büyük bir düz dosya var. Mysql bir normalize veritabanına düz bir dosya dönüştürmek. Düz bir dosya birkaç milyon hatları vardır.

Düz dosya alınırken ben aslında bir ORM sistemi kullanmaya çalıştı. Hatta nesnelerin dikkatli serbestleştirilmesi ile bu tasarım ile büyük bir php bellek sızıntısı sorunu vardı. Ben yeterli bellek olduğunu sağlamış olsa bile, komut benim masaüstünde çalıştırmak için yaklaşık 25 gün sürer.

Ben yükünü dışarı çıkardı ve doğrudan mysql komutları oluşturmak için komut dosyası yeniden yazdı. Bu Mysql ne son id girilen veri noktaları arasındaki ilişkileri yapmak için olduğu gibi bana gerekli beri Ben tasarım AUTO INCREMENT kaldırıldı. Ben sadece yerine veritabanı kimlikleri için küresel bir sayacı kullanmak ve herhangi aramalarını yapmak asla, sadece ekler.

Ben unix tekrar ve tekrar bir dosya işaretçisi kullanarak ilişkili bir bellek yükü olduğundan, küçük dosyalar yerine büyük bir bir sürü yapmak için komutu bölünmüş kullanın.

Bu iyileştirmeleri kullanarak yaklaşık 6 saat çalıştırmak için ithalat komut dosyası var (onlar başkası yardımcı umuyoruz).

Benim masaüstünde göre 5 kat daha fazla RAM ve yaklaşık 5 kat daha fazla işlemci gücü ile sanal bir örneği kiraladı ve tam olarak aynı hızda gittiğini fark ettim. Sunucu işlemi çalışır ama CPU döngülerini ve yedek RAM bulunuyor. Belki de sınırlayıcı faktör diski hızıdır. Ama RAM'i var. Ben bir şekilde belleğe dosyaları yükleyerek denemek mi? Büyük dosyaları işleme php komut satırı komut daha optimizasyonu için herhangi bir öneri bekliyoruz!

4 Cevap

Hoşuna ama eldeki görev için yanlış bir dil kullanıyor gibi ... sesler olmaz. Eğer hız bazı büyük sıçramalar almak istiyorsanız o zaman derlenmiş bir dil için bir liman gitmek için bir sonraki adım olacaktır. Derlenen diller hiç böylece işlem süresi düşüyorlar göreceksiniz bir betik dili daha hızlı, çok daha çalıştırın.

Ayrıca komuta bir yapı kullanarak veritabanına veri dökümü mümkün olabilir. Postgres bir (Dump? Böyle bir şey yükleyin) tablodaki sütunları ile eşleşen sütunlar olan bir sekme ayrılmış metin dosyası okumak hangi vardı. Yani sadece sağ biçiminde bir metin dosyası alma ve daha sonra tek bir komut ile DB içine tükürme ve oldukça kendinizi daha bunun optimizasyonu halledeyim odaklanmak için izin verecek.

Sen ihtiyaç olmamalı, kafasına ORM vurma dosya bölme ile doğru olanı yaptık ama hiç önemli değil "gerektiğini" böylece metin dosyası okuyucu sadece dahili bir tampon kullanmanız gerekir ama ben bir * nix adam değilim gibi böylece ön yanlış olabilir.

Biz, her satırda RegExp yaparken her sabah dosyaları 20GB yoluyla chomps bir. Net uygulaması ile benzer bir şey benzersiz kayıtları için bir bellek karma tutar ve daha sonra bir veritabanına yenilerini dürter ettik. O biz o zaman (bu yavaş parçası olan) kolaylığı için bir Ruby Script kullanarak 9000 + JS dosyaları tükürmek. Biz ithalatçı de Ruby yazılı olması için kullanılan ve her şey, yeniden yazma 3 + saat aldı. Net çalıştırır tüm süreci yaklaşık 30-40 dakika içinde ve bu 20 yavaş Ruby komut dosyası (optimize değer değil artık bir bu işi yeterince iyi) yok ama.

Böyle bir görev için önemli tasarım önerileri bir çift:

Kerede belleğe dosyanın tamamını okumaz. Bir dosya gösterici kullanmak ve makul parçalar okumak (diyelim ki bir kaç kilobayt .. ortalama rekor büyüklüğüne bağlıdır). Sonra her kayıt işlemek ve tampon dışarı hendek. Ben zaten bu ya da değil yapıyoruz olmadığını açıklamasından emin değilim.

MySQL depolama türü işlemleri (tablo InnoDB olmalı) destekliyorsa, optimizasyonlar için bunları kullanabilirsiniz. Bir işlem ve süreç f.ex. başlayın 100k satır, daha sonra işlem yapılıyor ve yeni bir tane açarak yıkayın. MySql yerine sadece her satır için bir kez indeksi güncelleyecek Bu çalışıyor çünkü.

Başka bir seçenek kütle ekleme kullanmaktır. Veritabanı (örneğin eğer ağ üzerinden bağlantı) yerel değilse, bu bir destek verebilir. Hatta MyISAM tabloları için muhtemelen - I (emin değilim ama) o da işlemler gibi aynı faydaları verir düşünüyorum.

Sonunda başka bir şey çalışıyorsa, sen denklemden php kaldırabilirsiniz ve LOAD DATA INFILE kullanın. Siz php veya başka bir metin işleme dili (awk veya sed çok iyi performans profilleri var) kullanarak, ilk dosyayı ön süreci gerekebilir

Eğer farklı makineler arasında benzer beeing, harcama zamanı, çünkü PHP script ve MySQL sunucu arasındaki iletişimin olabilir: Her MySQL istek için:

  • Eğer PHP komut dosyası oluşturma isteği (makinenin gücüne bağlıdır, ama gerçekten hızlı)
  • (; takes time ağa veya yerel soket aracılığıyla) MySQL sunucusu bu isteği göndermek zorunda
  • MySQL sunucu (..., güvenlik için kilit var kullanmak, dizin oluşturmak, saklamak) veri ile başa çıkmak zorundadır
  • (:, Yani, yavaş ağ veya soket aynı) cevap ("ok", eklenen veri) geri PHP gitmek zorunda
  • ve her zaman tüm bu yok.

Ne zaman alır PHP tarafında gerçekten büyük olasılıkla değildir; muhtemelen, PHP ve MySQL arasındaki - ve hiçbir kadar bu konuda yapabileceğimiz bir şey olabilir.

Eğer oldukça güçlü bir makine varsa, ne öneririm olduğunu:

  • X verilerinizi bölünmüş, parça (değil çok adam X = 6 örneğin demek)
  • Eğer bir parametre olarak üzerinde çalışmak gerektiğini parçanın numarasını vererek, paralel bunu 6 kez başlatmak böylece PHP komut değiştirmek.
  • scripti 6 kez launche.

Senaryonun ilk paralel yürütme 6 kat daha az veri ile uğraşacağız; diğerleri ... Ve sonunda, paralel çalışacak ... Peki için aynı, tüm süreç :-) belki 4 kat daha az zaman alacak

Muhtemelen 6 kat daha az zaman almayacaktır: parallelisation ile çalışan makinede bazı yük eklenmesi anlamına gelir, ve MySQL eşzamanlılık bazı istekleri olacak - ama paralel süreçlerin sadece bir çift ile, iyi olacak.

Bir yan not olarak: PHP bunu yapmanın en iyi şey olmayabilir. Burada düşünmek başka bir yoludur:

  • use a script (like PHP or Perl or shell or whatever) to :
    • girdi dosyaları okumak
    • insert istekleri oluşturmak (ancak MySQL sunucusuna göndermek)
    • Bir dosya için bu yazma istekleri
  • when all the request for the millions of lines are in the file :
    • bir atış, MySQL için bu dosyadaki, başlatın.
    • Böyle bir şey komut satırında, yapardı: "mysql --host=HOST --user=USER --password=PASSWORD DATABASE_NAME < inserts-commands.sql"

- Gerçekten hızlı gitmeli, her istek için MySQL PHP gitmek zorunda değilsiniz: Bu yol, sadece SQL istekleri dosyasında Tamam, ve sonra, MySQL bir çekimde her şeyi ithal ediyor emin olun.

Bu yardımcı olur umarım eğlenin!

Script Optimizasyonları dışında herhangi bir PHP hızlandırıcı denemek için öneririm (örn: eaccelerator.net). Bu işe yaramazsa ben bu tür görevlere için yapılmış bir dil / platform kullanmanızı öneririm.