Daha hızlı, büyük bir sorgu veya birçok küçük sorgu nedir?


68

Farklı şirketler için çalışıyorum ve bazılarının tüm "akrabaları" ile bir masaya katılacak görüşlere sahip olmayı tercih ettiklerini fark ettim. Ancak daha sonra uygulamada bazı zamanlar sadece 1 sütun kullanmamız gerekir.

Öyleyse basit seçimler yapmak daha hızlı olur mu ve sonra sistem kodunda onlara "katılın" mı?

Sistem php, java, asp, veritabanına bağlanan herhangi bir dil olabilir.

Öyleyse asıl soru, bir Sunucu Tarafından (php, java, asp, ruby, python ...) veritabanına hızlı giden şey, ihtiyacımız olan her şeyi alan sunucudan veritabanına giden bir sorguyu çalıştırmak ve sadece bir tablodan sütunları alan sorgu?


2
Hangi 'SQL' uygulamasını kullanıyorsunuz? MySQL, Microsoft SQL Sunucusu, Oracle, Postgresql, vb. Lütfen etiketinizi güncelleyin.
RL

1
Mysql ve Postgresql
sudo.ie

6
Benim deneyimim, MySQL'in karmaşık sorguları sevmediği ve genellikle çok basit sorgularla (ancak daha fazla) daha hızlı olduğu yönünde. Postgres'in sorgu iyileştiricisi çok daha iyi ve orada genellikle tek bir büyük sorguyu çalıştırmak daha verimli.
a_horse_with_no_name

3
@ a_horse_with_no_name Özellikle bu soru bağlamında çok genel bir genelleme. MySQL optimizer gerçekten de tasarım açısından oldukça basittir ve PostgreSQL'de daha hızlı planlar yapan, özellikle MySQL'in daha eski sürümlerinde, PostgreSQL'de daha hızlı planlar yapan MySQL saf OLTP yükleri için çok hızlı olabilir. Bununla birlikte, soru bağlamında, tek bir büyük sorgu daha hızlı olacaktır, diyelim ki - mümkün olan en kötü senaryoda - bir programlama döngüsü içinde bir SELECT (kullanılan RDBMS ne olursa olsun).
jynus

2
@jynus: kuyu, soru olan çok geniş (plus: Ben "benim durumumda" dedi - Başkalarının farklı deneyimleri olabilir). Bir LOOP içindeki sorgu hiçbir zaman iyi bir fikir değildir ve neredeyse her zaman tasarımın zayıf olması veya ilişkisel bir veritabanıyla nasıl çalışılacağının anlaşılmamasının sonucudur.
a_horse_with_no_name

Yanıtlar:


69

Sorunuza cevap verecek konu JOIN DECOMPOSITION.

Kitabın 209. Sayfasına Göre

Yüksek Performanslı MySQL

Çok birleşimli birleştirme yerine birden çok tekli tablo sorgusu çalıştırarak ve ardından uygulamadaki birleştirme işlemini gerçekleştirerek bir birleşimi ayrıştırabilirsiniz. Örneğin, bu tek sorgu yerine:

SELECT * FROM tag
JOIN tag_post ON tag_post.tag_id = tag.id
JOIN post ON tag_post.post_id = post.id
WHERE tag.tag = 'mysql';

Bu sorguları çalıştırabilirsiniz:

SELECT * FROM tag WHERE tag = 'mysql';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN (123,456,567,9098,8904);

Neden bunu dünyada yapıyorsun? İlk bakışta savurgan görünüyor, çünkü karşılığında hiçbir şey almadan sorgu sayısını arttırdınız. Bununla birlikte, böyle bir yeniden yapılandırma aslında önemli performans avantajları sağlayabilir:

  • Önbellekleme daha verimli olabilir. Birçok uygulama, doğrudan tablolarla eşleşen "nesneleri" önbelleğe alır. Bu örnekte, etiketli nesne mysqlzaten önbelleğe alınmışsa , uygulama ilk sorguyu atlayacaktır. Önbellekte 123, 567 veya 908 kimliği olan gönderiler bulursanız, bunları IN()listeden kaldırabilirsiniz . Sorgu önbelleği de bu stratejiden yararlanabilir. Tablolardan yalnızca bir tanesi sık sık değişirse, bir birleşimin ayrıştırılması, önbellek geçersiz kılma sayısını azaltabilir.
  • Sorguları tek tek yürütmek bazen kilit sürekliliğini azaltabilir
  • Uygulamaya katılma işlemleri, farklı sunuculara tablolar yerleştirerek veritabanını ölçeklendirmeyi kolaylaştırır.
  • Sorguların kendileri daha verimli olabilir. Bu örnekte, IN()bir birleştirme yerine bir listenin kullanılması, MySQL'in sıra kimliklerini sıralamasına ve bir birleşimde mümkün olabileceğinden daha iyi bir şekilde satırları almasına izin verir.
  • Gereksiz satır erişimlerini azaltabilirsiniz. Uygulamada bir birleştirme yapmak, her satırı yalnızca bir kez almak anlamına gelir, oysa sorgudaki bir birleşme, esasen aynı verilere tekrar tekrar erişebilecek bir denormalizasyondur. Aynı nedenden ötürü, böyle bir yeniden yapılandırma toplam ağ trafiğini ve bellek kullanımını da azaltabilir.
  • Bir dereceye kadar, bu tekniği iç içe geçmiş döngü algoritması yerine bir karma birleşimini el ile uygulamak olarak görebilirsiniz, MySQL bir birleşim yürütmek için kullanır. Bir karma katılım daha verimli olabilir.

Sonuç olarak, daha önce yapılan sorgulardan çok fazla veri önbelleğe aldığınızda ve bunları yeniden kullandığınızda, birden çok sunucuya veri dağıtırken, birleştirme işlemlerini IN()listelerle değiştirdiğinizde veya bir birleştirme aynı tabloya birden çok defa başvurduğunda, uygulamadaki katılımlar daha verimli olabilir .

GÖZLEM

İlk madde işaretini seviyorum, çünkü InnoDB sorgu önbelleğini geçtiğinde biraz el aldı.

Son madde işaretine gelince, iç içe geçmiş döngü algoritmasını tanımlayan 11 Mart 2013 tarihinde bir JOIN koşulu ve bir WHERE koşulu arasında bir yürütme farkı var mı? ). Okuduktan sonra, birleşme bozulmasının ne kadar iyi olabileceğini göreceksiniz.

Kitaptaki diğer tüm noktalara gelince , geliştiriciler gerçekten performans olarak alt satırda görünüyor. Bazıları, hızlı disk kullanma, daha fazla CPU / Çekirdek alma, depolama motorunu ayarlama ve yapılandırma dosyasını ayarlama gibi performans geliştirmeleri için harici araçlara (uygulamanın dışında) güveniyor. Diğerleri çökertecek ve daha iyi kod yazacak. Bazıları Saklı Prosedürlerde tüm iş zekasını kodlamaya başvurabilir, ancak birleşik ayrıştırma uygulayamazlar (Bkz . Diğer mantıklarla birlikte uygulama mantığını veritabanı katmanına koymanın veya bunun için ne gibi argümanlar var? ). Her şey, her geliştirici dükkanının kültürüne ve toleransına bağlı.

Bazıları performanstan memnun olabilir ve artık koda dokunmuyor olabilir. Diğerleri basitçe, kompozisyona katılmaya çalışırlarsa elde edebileceğin büyük faydalar olduğunun farkında değilsin.

İstekli geliştiriciler için ...

BİR ŞANS VER !!!


3
3 sorguya geçmekle ilgili bu bağlantıya gelince ... Baron, Vadim ve Peter'ı biliyorum ve saygı duyuyorum ama bu yanıltıcı öneriye katılmıyorum. Ayrılma lehine savların çoğu, değinmeye değmeyecek kadar nadirdir. JOIN'lerle tek bir sorguda kal, sonra onu geliştirmeye çalışalım.
Rick James,

2
@RickJames Yorumunuzun ruhuna katılıyorum. Yıllar boyunca, bazılarının parçalanma işine katıldığını ve diğerlerinin başarısız olduğunu gördüm. Uygun SQL skillset ile bile, birleştirme ayrıştırması doğru yapılmazsa size karşı işe yarayabilir. Şu andaki işverenimde, pek çok kişi, özellikle eski yasalar söz konusu olduğunda ve derin cepler mevcut olduğunda, ölçeklendirme aşkını yukarı ve dışa doğru seviyorum. Havyar tadı olan ancak yumurta salatası bütçesine sahip olanlar için, ayrıştırmaya katılmak riske değer olabilir ancak doğru yapılması gerekiyor.
RolandoMySQLDBA

Haklarım ve zamanım olsaydı bunun Oracle ortamında nasıl çalıştığını görmek isterdim.
Rick Henderson

Daha hızlı olmasının bir başka yolu da, sipariş verirseniz, büyük bir listeyi sipariş etmekten daha küçük listeler sipariş etmenin genel olarak daha az hesaplama yapmasıdır.
Evan Siroky

24

In Postgres (ve muhtemelen benzer bir ölçüde herhangi RDBMS, bir dereceye kadar MySQL), daha az sorguları neredeyse her zaman çok daha hızlı.

Birden çok sorguyu ayrıştırma ve planlama ek yükü, çoğu durumda zaten olası herhangi bir kazancından daha fazladır.

Müşteride yapılacak ek işlerden bahsetmemek, genellikle bu konuda çok daha yavaş olan sonuçları birleştirmek . Bir RDBMS bu tür görevlerde uzmanlaşmıştır ve işlemler orijinal veri türlerine dayanmaktadır. textAra sonuçlar için geri dönüş veya geri dönüş yok veya müşterinin doğal türüne dönüşüyor, bu da daha az doğru (veya yanlış!) Sonuçlara yol açabiliyor. Kayan nokta sayılarını düşünün ...

Ayrıca, DB sunucusu ve istemci arasında daha fazla veri aktarın. Bu, değerlerle dolu bir el için önemsiz olabilir veya çok büyük bir fark yaratabilir.

Birden fazla sorgu, veritabanı sunucusuna çok sayıda tur atılması anlamına geliyorsa, ağ gecikmesinin ve işlem ek yükünün, muhtemelen ek yük bağlantısının birkaç katı toplarsınız. Büyük, büyük kayıp.

Kurulumunuza bağlı olarak, yalnızca ağ gecikmesi büyüklük sırasına göre diğerlerinden daha uzun sürebilir.

SO ile ilgili soru:

Çok büyük , uzun süre çalışan sorgular için bir dönüm noktası olabilir , çünkü işlemler yolda DB satırlarında kilitler toplar. Çok büyük sorgular, uzun süre boyunca birçok kilit tutabilir ve bu da eşzamanlı sorgular ile sürtünmeye neden olabilir .


Sadece meraktan, çok büyük ne düşünüyorsun ?
Sablefoste

@Sablefoste: Çok fazla erişim kalıplarına bağlıdır. Kritik bir nokta, eşzamanlı işlemlerin sıraya girmeye başlaması, kilitlerin serbest bırakılmasını beklemektir. Veya kaynaklarınızın önemli bir bölümünü yemek için yeterli kilit biriktirirseniz. Veya sorularınız otovacuum'la etkileşime girecek kadar uzun sürerse ...
Erwin Brandstetter

Ancak, biraz tipik bir durum alırsak - bir dış birleşim kullanan ve "ana" tablo için fazladan fazla veri döndüren bir sorgu varsa, bu durumda uygulamanın (büyük olasılıkla, bazı ORM kitaplıklarının) karşılaştırması ve çözümlemesi gerekir. önce gerekli tüm kimlikleri alan küçük seçim, ardından dış birleştirme yerine IN () ile başka bir küçük seçim? İkinci yaklaşım daha verimli olmayacak mı (hem DB hem de uygulama tarafından kullanılan CPU ve iletişim bant genişliği dikkate alındığında)
JustAMartin

1
@JustAMartin: RDBMS'nin sorgu planlamacısı tarafından ele alındığında - kesinlikle doğru sorgular varsayarsak, neredeyse kesinlikle daha hızlı olan bir sorgu türü gibi geliyor. Endişe verici returns lots of redundant data for "parent" table: Neden gereksiz verileri geri aldınız? Sadece ihtiyacınız olan verileri iade edin.
Erwin Brandstetter

1
Dış birleştirme ile RDBMS, her bir birleştirilmiş çocuk için çoğaltılan ana tablodan veri döndürür; bu, bazı ağ ve bellek ek yükü anlamına gelir ve daha sonra, çoğaltılmış ana değerlerini atmak ve yalnızca bir ebeveyni çocuklarıyla tutmak için ORM aracında bazı ek ayrıştırma anlamına gelir. Bu nedenle, tek bir sorgu ile, RDBMS sorgu planlayıcısının verimli çalışmasından tasarruf etmekteyiz, daha az ağ (veya yerel boru) talepleri kaybederiz, ancak gereksiz ek yükten kaybederiz ve ORM kütüphanesinde verileri kaydırırız. Sanırım, her zaman olduğu gibi - optimizasyondan önce önlem alın.
JustAMartin,
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.