PHP'den MySQL'e bağlanmak son derece yavaş


19

Yeni bir XAMPP kurulumu yaptım. İlk PHPMyAdmin açarken son derece yavaş olduğunu fark ettim. Localhost'ta her sayfanın açılması yaklaşık 5 saniye sürmesi mantıklı değildi. Suçu PHPMyAdmin'den çıkarmak için küçük bir test davası yaptım:

$con = new PDO("mysql:host=localhost;dbname=mysql", "root", "");
$statement = $con->query('SELECT host,user,password FROM user;');
$users = $statement->fetchAll(PDO::FETCH_ASSOC);

Yukarıdaki komut dosyasının çalıştırılması sadece 3 saniye sürer (ilk çalıştırdığımda yüklemek 8 saniyeye yaklaşmasına rağmen).

Sonra mysql_connectbunun yerine kullanmayı denedim PDO hatası olup olmadığını kontrol etmek için :

$con = mysql_connect("localhost", "root", "");
mysql_select_db("mysql", $con);
$result = mysql_query('SELECT host,user,password FROM user;');

Tamamlanması kadar uzun sürer.

Ben ilk başta PHP'nin hatası olduğunu düşündüm, ancak PHP kodu ve statik dosyaları yenileme tıklayabilirsiniz daha snappier sunulmaktadır. Ben bu küçük komut dosyası çalıştırarak PHP test:

header("Content-Type: text/plain");

for($i = 0; $i < 5000; $i++)
{
    echo sha1(rand()) . "\n";
}

5000 sha1hesaplamalar ve sayfa hala penceremi yenilemek daha snappier görüntülenir.

Sonra MySQL'in hatası olduğunu anladım. Ama yine de, MySQL'in ihtiyacımdan daha hızlı çalıştığını anlamak için fazla test yapmadım. MySQL CLI istemcisini kullanarak kullanıcı seçme sorgusu ölçülebilir zaman bile almaz - dönüş anahtarını bile bırakmadan önce yapılır.

Sorun PHP'nin MySQL ile bağlantısı olmalıdır - bu sebeple aklıma geldi. PHP yavaş ya da MySQL yavaş hakkında tonlarca şey bulabilirsiniz, ama PHP + MySQL son derece yavaş hakkında hiçbir şey.

Bunu çözmeme yardımcı olabilecek herkese teşekkürler!


Win32 için XAMPP 1.8.0 kullanıyorum ( İndirme linki )
PHP sürümü: 5.4.4
MySQL sürümü: 14.14


EDIT: Zamanlama sonra, çok uzun süren bağlantı işlevi olduğu ortaya çıkıyor:

$time = microtime(true);

$con = mysql_connect("localhost", "root", "");
mysql_select_db("mysql", $con);

$con_time = microtime(true);

$result = mysql_query('SELECT host,user,password FROM user;');

$sel_time = microtime(true);

printf("Connect time: %f\nQuery time: %f\n",
       $con_time-$time,
       $sel_time-$con_time);

Çıktı:

Bağlantı süresi: 1.006148
Sorgu süresi: 0.000247

PHP'nin veritabanına bağlanmak için çok fazla zaman harcamasına ne neden olabilir? CLI istemcisi, HeidiSQL ve MySQL çalışma tezgahı anında bağlanır


php -m çıktı lütfen
düşünmek

Yanıtlar:


17

MySQL'iniz her bağlandığınızda rev-dns sorgusunu çalıştırmaya çalışabilir mi? my.cnf, mysqld: skip-name- resol bölümüne eklemeyi deneyin .


Garip bir şekilde hem PHPMyAdmin hem de MySQL CLI istemcisi bana "Host '127.0.0.1' 'in bu MySQL sunucusuna bağlanmasına izin verilmiyor" veriyor. Nedense PHP betiği hala çalışıyor, ama eskisi kadar yavaş
Hubro

benzeri mysql tezgahını yönetmek için 'yağ uygulamaları' yavaş mı?
pQd

MySQL Workbench'ten aynı sorguyu çalıştırmak CLI istemcisi kadar hızlıdır ve HeidiSQL
Hubro

php biraz zamanlama ekleyin ve bağlanma veya çok zaman alır sorguyu çalışıp çalışmadığını kontrol edin.
pQd

Bu yorum için teşekkürler, sorumu güncelledim. Hem bağlantı hem de sorgu süper hızlı
Hubro

30

Bu, buradaki cevabımdan neredeyse kelimesi kelimesine alınmış , ancak SO'ya sadece link cevaplarına kaşlarını açtığımızı biliyorum, bu yüzden siz de yaptığınızı hayal ediyorum :-)

Bu sorunu yaşıyorsanız ve Windows 7'den önce bir Windows sürümü kullanıyorsanız, bu muhtemelen sorunun cevabı değildir.

Bu neden oluyor?

Bu sorunun nedeni IPv4 ve IPv6'dır.

IP adresi yerine bir ana bilgisayar adı kullandığınızda, MySQL istemcisi önce AAAAad için bir (IPv6) ana bilgisayar araması çalıştırır ve adı başarıyla bir IPv6 adresine çözerse bu adresi dener. Adımlardan biri başarısız olursa (ad çözümlemesi veya bağlantı) IPv4'e geri döner, bir Aarama çalıştırır ve bunun yerine bu ana bilgisayarı dener.

Uygulamada bunun anlamı, IPv6 localhostaraması başarılı ancak MySQL'in IPv6 geridönüşüne bağlı olmaması durumunda, IPv4 geri dönüşü gerçekleşmeden ve bağlantı başarılı olmadan önce bir bağlantı zaman aşımı döngüsü beklemeniz gerekecektir.

Bu, Windows 7'den önce bir sorun değildi, çünkü localhostçözünürlük anasistemler dosyası üzerinden yapıldı ve yalnızca önceden yapılandırılmış olarak geldi 127.0.0.1- IPv6 karşılığı ile gelmedi ::1.

Bununla birlikte, Windows 7'den bu yana, buradalocalhost özetlenen nedenlerle çözümleme DNS çözümleyicisine yerleştirilmiştir . Bu, IPv6 aramasının başarılı olacağı anlamına gelir - ancak MySQL bu IPv6 adresine bağlı değildir, bu nedenle bağlantı başarısız olur ve bu soruda belirtilen gecikmeyi göreceksiniz.

Bu iyi. Bana bunu nasıl düzeltebileceğimi söyle!

Birkaç seçeneğiniz var. İnternete baktığımızda, genel "çözüm" IP adresini ad yerine açıkça kullanmak gibi görünüyor, ancak bunu yapmamanın birkaç nedeni var, her ikisi de taşınabilirlikle ilgili, her ikisi de tartışmasız önemli değil:

  • Komut dosyanızı yalnızca IPv6'yı destekleyen başka bir makineye taşırsanız, komut dosyanız artık çalışmaz.

  • Komut dosyanızı * nix tabanlı bir barındırma ortamına taşırsanız, sihirli dize localhostMySQL istemcisinin yapılandırılmışsa bir Unix soketi kullanmayı tercih edeceği anlamına gelir, bu IP geri döngü tabanlı bağlantıdan daha verimlidir

Kulağa oldukça önemli geliyorlar mı?

Onlar değil. Uygulamanızı bu tür şeyleri bir yapılandırma dosyasında tanımlanacak şekilde tasarlamalısınız. Komut dosyanızı başka bir ortama taşırsanız, başka şeylerin de yapılandırılması gerekecektir.

Özetle, IP adresini kullanmak en iyi çözüm değildir , ancak büyük olasılıkla kabul edilebilir bir çözümdür.

Peki en iyi çözüm nedir?

En iyi yol, MySQL sunucusunun kullandığı bağlanma adresini değiştirmek olacaktır. Ancak, bu istendiği kadar basit değil. Apache, Nginx ve şimdiye kadar yapılmış olan diğer tüm akılcı ağ hizmeti uygulamalarının aksine, MySQL yalnızca tek bir bağlanma adresini destekler, bu yüzden sadece başka bir adres ekleme durumu değildir. Neyse ki, işletim sistemleri burada biraz büyü destekliyor, bu nedenle MySQL'in hem IPv4 hem de IPv6'yı aynı anda kullanmasını sağlayabiliriz.

MySQL 5.5.3 veya üstünü çalıştırıyor olmanız ve MySQL'i --bind-address=komut satırı argümanıyla başlatmanız gerekir . Ne yapmak istediğinize bağlı olarak 4 seçenek belgeniz var:

  • Muhtemelen aşina olduğunuz ve muhtemelen (etkili bir şekilde) kullandığınız 0.0.0.0. Bu, makinedeki tüm kullanılabilir IPv4 adreslerine bağlanır. IPv6'yı önemsemeseniz bile, muhtemelen bu en iyi şey değildir, çünkü aynı güvenlik risklerine maruz kalır ::.

  • Açık bir IPv4 veya IPv6 adresi (örneğin 127.0.0.1veya ::1geri döngü için). Bu, sunucuyu bu adrese ve yalnızca bu adrese bağlar .

  • Sihirli dize ::. Bu, MySQL'i IPv4 ve IPv6 modunda hem geri döngü hem de fiziksel arabirim adresleri üzerindeki her adrese bağlar. Bu muhtemelen bir güvenlik riskidir, bunu yalnızca uzak ana bilgisayarlardan gelen bağlantıları kabul etmek için MySQL'e ihtiyacınız varsa yapın.

  • Bir kullan IPv4 eşlenmiş IPv6 adresini . Bu, 4 -> 6 geçişi sırasında geriye dönük uyumluluk için IPv6'ya yerleşik özel bir mekanizmadır ve belirli bir IPv4 adresine ve IPv6 eşdeğerine bağlanmanıza olanak tanır. Bunun, "çift geri döngü" adresi dışında herhangi bir şey için yararlı olması pek olası değildir ::ffff:127.0.0.1. Bu büyük olasılıkla çoğu kişi için en iyi çözümdür, yalnızca geri dönüşe bağlanır, ancak hem IPv4 hem de IPv6 bağlantılarına izin verir.

Hosts dosyasını değiştirmem gerekir mi?

HAYIR . Hosts dosyasını değiştirmeyin. DNS çözümleyicisi ne yapılacağını bilir localhost, yeniden tanımlamanın en iyi etkisi olmaz ve en kötü ihtimalle çözümleyicinin kafasını karıştırır.

Ne olmuş --skip-name-resolve?

Bu, ilgili ancak biraz farklı bir nedenden dolayı sorunu çözebilir.

Bu yapılandırma seçeneği olmadan, MySQL tüm istemci bağlantısı IP adreslerini bir PTRDNS sorgusu aracılığıyla bir ana bilgisayar adına çözümlemeye çalışır . MySQL sunucunuz zaten IPv6 kullanabiliyorsa, ancak bağlantılar uzun sürüyorsa, bunun nedeni ters DNS ( PTR) kaydının doğru yapılandırılmamış olması olabilir.

Ad çözümlemesinin devre dışı bırakılması bu sorunu düzeltir, ancak özellikle koşulda bir DNS adı kullanmak üzere yapılandırılmış erişim izinlerinin Hostbaşarısız olacağı başka etkileri de vardır .

Bunu yapacaksanız, tüm hibelerinizi adlar yerine IP adreslerini kullanacak şekilde yapılandırmanız gerekir.


2
En sonunda! Teşekkür ederim teşekkür ederim! Sonunda tüm nedenlerin, olası çözümlerin ve bunların karşı konularının doğru, eksiksiz ve net bir açıklamasını buldum. Bununla ilgili bir kitap yazmalısın!
tobia.zanarella

4
Bağlama adresini değiştirene kadar localhost'ta MySQL'e bağlanmada 1 saniyelik bir gecikme yaşıyordum ::1. Ne yazık ki ::ffff:127.0.0.1bana 1 saniye gecikme vermeye devam ettiniz (kullanıp kullanmamaya bakılmaksızın skip-name-resolve), neden herhangi bir fikir? (Windows 8.1'de)
Simon East

1
@Simon Bakmadan bir ipucu değil, ancak hata ayıklamanın ilk adımı, MySQL'in her iki yığınta gerçekten dinlediğini ve bağlanabilir olduğunu doğrulamak için doğrudan açık adresleri kullanarak hem IPv6 geri döngüsüne hem de IPv4 geri döngüsüne bağlanmaya çalışmak olacaktır. .
DaveRandom

1
evet, :: ffff: 127.0.0.1 çalışmıyor ...
Raheel Hasan

Eğer :: 1 ile bağlarsam, Sqlyog çalışmıyor ... ne yapmalı ??
Raheel Hasan

13

Genellikle IPv6, MySQL'e sunucu bağlantılarında etkinleştirildiğinde, localhostkullanımı oldukça yavaştır.

127.0.0.1Sorunu çözmek için koddaki mysql sunucu adresini değiştirmek .


+1 bu benim için doğru cevaptı. Sanırım Windows 8'de çözünürlüğü localhostDNS çözümleyicisine taşıdılar, çünkü @DaveRandom şu bağlantıya bağlandı: serverfault.com/questions/4689/…
wwarren

Benim için çalıştı: D
FosAvance

Bu, diğer sunucular için de olabilir localhost. Formda bir sunucu adresi için aynı gecikme sorunu vardı xx.xxxx.xxxxx.xxxxx.com. Sunucu adını IP adresine değiştirdikten sonra sorun ortadan kalktı.
Gruber

1
mysql_connect("localhost", "root", "");

Nedenin ne olduğu oldukça açık. PHP bazı şeylerde gerçekten iyi, ancak 'localhost'u doğrudan' 127.0.0.1 'e çevirmede değil. PHP'nin HOSTS dosyanızı kontrol etmesini ve 'localhost'un arkasındaki gerçek IP adresini almak için ne yapmamasını engellediğinden, web sitesi sayfanızın yüklenme süresini gerçekten azaltacağını denemeniz gerekir.


Sorunun ne olduğunu önermeye çalıştığınızı anlayamıyorum.
kasperd

@kasperd DNS 'localhost' çözme
Xesau

'17 - mysql_ * fonksiyonundan not şimdi kaldırıldı ve php7
treyBake


0

Ayrıca, db bağlantı değişkeninizde küçük bir ayar yaparak (bu da taşınabilirlik için komut dosyalarınızdan ayrı bir dosyadadır) sorgu yavaşlamasını ortadan kaldırabilirsiniz. Ana bilgisayar değerini "localhost" yerine "127.0.0.1" olarak değiştirin. Bu, localhost için uzun DNS aramasını atlar.

Bu yardımcı olur umarım!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.