Kodda “çok fazla veritabanı isteği” olan özellikler nelerdir?


17

Bu kendim ve bazı meslektaşlarımın tartıştığı ve buraya gelip genel bir fikir birliği olup olmadığını göreceğimizi düşündüm.

Temel olarak veritabanı çağrıları hakkında aşağıdaki 2 görüşe gelir: 1. DB çağrı sayısını azaltmak için gerekli olabilecek her şeyi almak için büyük bir çağrı yapın 2. Büyüklüğünü azaltmak için talep edilene göre daha küçük ayrı çağrılar yapın DB çağrıları

Bunun özellikle devreye girdiği yer ortak koddadır. Oldukça basit olan bir Çalışan sınıfı örneğini kullanacağız.

Çalışan sınıfınızda 10 değer özniteliği (ad, soyadı, kiralama tarihi vb.) Ve sonra 2 sınıf özniteliği olduğunu varsayalım ... 1 bir Departman sınıfına işaret eder ve daha sonra başka bir Employee nesnesine işaret eden 1 süpervizör.

Zihniyet # 1'de, Çalışan verilerini ve Departman ve Süpervizör niteliklerini doldurmak için gerekli alanları ... veya en azından bu alt nesnelerden en sık kullanılan alanları döndüren bir çağrı yaparsınız.

Zihniyet # 2'de, ilk olarak yalnızca Çalışan nesnesini doldurursunuz ve daha sonra yalnızca istendiğinde ve istendiğinde Bölüm ve Denetçi nesnelerini doldurursunuz.

2'nin duruşu oldukça basittir ... isteklerin boyutunu ve bu isteklerden biri her yapıldığında kaç veritabanı nesnesinin vurulması gerektiğini en aza indirin. # 1'in duruşu, düzgün bir şekilde uygulanabilse bile, kodun birden fazla bağlantı yapmak zorunda kalacağı gerçeği, web sunucusu ile veritabanı arasındaki bağlantıyı azaltmanın aksine daha fazla zorlanmaya neden olacağıdır.

Bunu araştırmanın arkasındaki itici güç, web sunucumuz ve veritabanı sunucumuz arasındaki trafik miktarının kontrolden çıkmasıdır.


7
Benim tecrübelerime göre, bunun doğru bir cevabı yoktur. Gecikme ve verim arasında bir denge vardır. Düşük gecikme, çok sayıda küçük talebi veya hatta bir büyük isteği tolere edebilir; ancak, yüksek gecikme süreleri, aynı anda çok fazla veri taşımaktan daha iyi olma eğilimindedir. Bununla birlikte, yüksek gecikme yapılandırmasında verim düşükse, daha duyarlı olmak için daha küçük parçaları almanız daha iyi olur.

3
Muhtemelen n + 1 problemiyle ilişkili stackoverflow.com/questions/97197/…
Valera Kolupaev

@Valera: kolaylık sağlamak için bu soruya gönderilen bağlantı: realsolve.co.uk/site/tech/hib-tip-pitfall.php?name=n1selects
rwong

4
"web sunucumuz ve veritabanı sunucumuz arasındaki trafik miktarı kontrolden çıkıyor." Bu ne anlama geliyor? Asıl sorunun ne olduğu konusunda net olabilir misiniz ? Performans sorunlarınız mı var? Profil oluşturma ve ölçme yaptınız mı? Lütfen sorunun bir parçası olarak gerçek ölçümlerden elde edilen gerçek sonuçları sağlayın. Aksi takdirde, sadece tahmin ediyoruz.
S.Lott

Yanıtlar:


8

Bu sorunun arkasındaki itici güç çok fazla trafik ise, sık kullanılan nesneleri önbelleğe almayı düşündünüz mü? Örneğin: Çalışan ve Departman ve Süpervizör nesnelerini aldıktan sonra, belki de önbellek eklemek iyi bir fikir olur, böylece yakın gelecekte tekrar istenmeleri durumunda zaten önbellekte olurlar ve alınmaları gerekmez tekrar. Elbette, önbelleğin nadiren kullanılan nesnelerin süresinin dolmasına izin vermesi ve ayrıca uygulama tarafından değiştirilen ve veritabanına kaydedilen nesneleri kaldırabilmesi gerekir.

Hangi dili ve çerçeveleri kullandığınıza bağlı olarak, ihtiyacınız olan şeylerden bazılarını (veya çoğunu) yapabilen bir önbellek çerçevesi zaten olabilir. Java kullanıyorsanız, Apache Commons-Cache'e bakabilirsiniz (bir süredir kullanmadım ve hareketsiz görünse de, hala kullanılabilir ve son kullandığımda oldukça iyi oldu).


3

İlk kez bir şey yazarken her zaman okunabilirlik ve netlik için gidin . Daha sonra ihtiyacınız olduğunda ve gerektiğinde yeniden düzenleyebilirsiniz. Darboğazları bulmak için yük testi yapın, birçok durumda soruna neden olan çağrıların sayısı değil, kötü yazılmış olanlar.

Çok fazla olarak neyin sınıflandırıldığına gelince, bu uygulamaya bağlıdır. Çoğu web uygulaması için 30 saniyenin altındaki herhangi bir şey hemen hemen kabul edilebilir. Kullanıcılarınızla beklentileri hakkında konuşurdum.


Kötü yazılmış bir db çağrısı nedir?
nu everest

3

Sorunuz, herhangi bir sayfa için hangi verilerin gerekli olacağını tahmin etmeniz gerektiği varsayımına dayanmaktadır. Konu bu değil. Bu saf yaklaşım kadar kolay değildir, ancak herhangi bir veritabanı çağrısı yapmadan önce departman veya süpervizör özelliklerine ihtiyacınız olup olmayacağını bilecek şekilde kodunuzu mimariye alabilirsiniz.


3

Bunlar benim kullandığım kurallar, belki onlar sizin için yararlı olacaktır.

  1. Önce ölçün! Aslında bu kaynağa akan trafik göremiyorsanız ve bu kaynak yavaş yanıt vermiyorsa "yavaş olabilir" koduna bile bakmayacağım.
  2. 1 İstek = K sorgusu. Veritabanıyla konuşma sayısı tam olarak istenen kaynak türüne göre belirlenir; ve asla bu kaynağın talebinin veya durumunun doğası gereği; Örneğin, bu muhtemelen en fazla 3 sorgudır: 1 Çalışanlar için, 1 Bölümler için ve 1 Süpervizörler için; Her birinin kaç tane olduğu önemli değil.
  3. Kullanmayacağınız şeyleri sorgulamayın . Bu, bahsettiğimiz HTTP ise, verileri daha sonra sorgulamak için bir anlamı yoktur; daha sonra yok; her talep temiz bir sayfadan başlar. Bazen bir tablodaki sütunların çoğuna ihtiyacım var , ama bazen sadece bir veya iki taneye ihtiyacım var; tam olarak ihtiyacım olan alanları bildiğimde, bunu isteyeceğim.
  4. Sorundaki donanımı atın. Sunucular ucuz; Bazen sadece veritabanını daha hareketli bir kutuya taşıyarak yeterli performans elde edebilirsiniz; veya bazı sorguları salt okunur bir kopyaya gönderme.
  5. Önce önbelleği geçersiz kılın, ardından önbelleğe alma işlemini uygulayın. Sıklıkla kullanılan veya sorgulanması zor olan verileri önbellekte koyma isteği güçlüdür; ancak çoğu zaman, kullanılmayan verileri çıkarmak veya geçersiz kılınan verilerin süresi dolmak göz ardı edilir. Verileri önbellekten nasıl çıkaracağınızı biliyorsanız; o zaman önbelleğe koymak güvenlidir; Önbelleği geçersiz kılmanın yalnızca sorguyu yapmaktan daha pahalı olduğu ortaya çıkarsa; önbelleğe ihtiyacınız yoktu.

2

Buradaki stratejilerin her ikisi de mükemmel bir şekilde geçerlidir. Her birinin avantajları ve dezavantajları vardır:

3 nesnenin tümü için bir çağrı:

  • daha hızlı performans gösterecek
  • İhtiyacınız olan yerde tam olarak ihtiyacınız olanı alırsınız
  • muhtemelen sadece bir durumda kullanılabilir (yine de çok yaygın bir durum olabilir)
  • bakımı daha zor olacak
  • (3 nesnenin şemalarından herhangi biri veya gerekli veri değişirse değişeceği için) daha sık bakım yapılması gerekir.

Nesne başına bir çağrı (toplam 3 çağrı)

  • Her nesne türünün tek bir örneğini doldurmak için genel amaçlı bir çağrı verir; daha sonra bağımsız olarak kullanılabilirler
  • Sorgu yapısı daha basit olacağından daha sürdürülebilir olacaktır.
  • Daha yavaş olacaktır (yavaşça 3 kat daha fazla olmamakla birlikte, aynı veriler için ek yük artırılmıştır)
  • Gereksiz verilerin alınmasıyla ilgili sorunlara neden olabilir (bir alana ihtiyacınız olduğunda kaydın tamamını almak israftır)
  • Birden fazla bire bir ilişki olduğunda N + 1 sorunlarına neden olabilir, tek kayıt sorgusu koleksiyonda her kayıt için bir kez N kez gönderilir.

Birkaç endişenize yanıt olarak (ikinci listede # 3 ve 5) ... Süpervizör ve Departman zamanın sadece 1 / 3'ünü (veya daha azını) kullanırsa ne olur? Kod, onları içerecek şekilde kodlanan List <> nesnesine ilk başvuruda bulunulduğu anda tüm çocukları alacak şekilde tasarlanmışsa ne olur? ... bu savaşın çoğunu kolaylaştırır mı?
user107775

Yardımcı nesnelere sadece nadiren ihtiyaç duyulursa, genel durumda bu daha hızlı performans gösterir (almak için daha az veri), ancak en kötü durum daha yavaş olacaktır (aynı veri veya daha fazla, bilgisayarınızdan iletişim yükünün üç katı kullanılarak). N + 1 problemine gelince, ilişkinin "bir" tarafındaki yabancı anahtara dayanarak bunu yapabilmek için bir nesne listesini alan sorguyu mimariye almanız ve ardından birden çok satır çekmeniz yeterlidir. sorgu sonucunun dışında. Kaydın birincil anahtarına sahip olması gereken bir sorgu sürümünü kullanamazsınız.
KeithS

1

Bana göre, çok fazla DB isteği, herhangi bir zamanda ihtiyacınız olan verileri yüklemeniz için gerekenden daha fazla istekte bulunuyor.

Bu yüzden verilere ihtiyacınız yok, daha sonra ikinci bir seyahatten kaçınmak için belleği boşa harcamayın. Ancak veri miktarına ihtiyacınız varsa, db çağrılarını en aza indirmelisiniz.

Her iki seçeneğe de sahip olun ve her birini durumun gerektirdiği yerlerde kullanın.

EDIT: Bu durumun sizin durumunuza da bağlı olduğunu unutmayın. Bu bir WebApp, örneğin WepApp için web genelinde aksine, ağınızdaki DB erişen bir masaüstü uygulaması daha farklı düşünmelisiniz.


Ortak kod yazmanız durumunda ve kodunuzun nasıl kullanılacağından emin değilseniz ne olur? Belki de Süpervizöre ihtiyaç duymayan birini düşünmezsiniz, ancak üzerinde çalıştığınız uygulamanın ihtiyacı olan tek şey olduğu ortaya çıkar. Tabii, ayrı fonksiyonlar yazabilirsiniz ... biri dahil etmemek için diğeri de dahil etmek için ama ortak kodunuz hangi noktada kullanmak için çok fazla ayrıntılı bilgi gerektiriyor?
user107775

@ user107775 Genellikle her durum için yalnızca iki işlev yazarım; biri yalnızca özellik değerlerini döndürür ve diğeri de ilgili tüm sınıflarla sınıfı döndürür. Çünkü ÇOK kez, sadece özelliklere ihtiyacınız var. Bu şekilde, ayrıntılı bilgiye ihtiyacınız yoktur, sadece bir tanesi temel bilgileri ve diğeri her şeyi alır. Makul bir denge olduğunu düşünüyorum. (Ancak bazı özel durumlar daha fazla optimizasyon gerektirir, ancak bu duruma göre).
AJC

1

DB'ye bağlanın, istek gönderin ve ayrıştırılmasını sağlayın, sonuçların alınmasına kıyasla genellikle önemli zaman alır, bu nedenle genel eğilim, bir istekte olabildiğince çok sorguyu birleştirmektir.

Yine de, tüm bunları tek seferde yapmak, kodu sürdürülemez hale getirecektir. Bunun yerine, genellikle ek bir soyutlama katmanı ile elde edilir: kod, gerektiğinde çeşitli istekleri zamanlar, daha sonra motor bunu büyük bir istek olarak ayrıştırır (muhtemelen yolda önbellek kullanarak) ve ardından yanıtlar gerektiği gibi gönderilir.

Tabii ki her zaman bir sorguda her zaman alınamaz - genellikle bir sonraki sorguyu oluşturmak için gerekli verileri sağlayan bir sorguya sahip olursunuz, bu yüzden tekrarlamanız gerekir. Hala sorgu demetlerini şaşırtmak ve aynı anda mümkün olduğunca çok şey gerçekleştirmek veritabanına yapılan yüzlerce küçük çekimden daha iyidir.

Bu nedenle, neye ihtiyacınız olduğunu planlayın, isteyin ve alın, daha fazlası gerekiyorsa, tekrar isteyin ve alın ve ardından içerik oluştururken verileri kullanın. Kodun her tarafına dağılmış yerel değişken başlatma gibi veritabanı isteklerini kullanmaktan kesinlikle kaçının.


1

Çok yakında optimizasyonu yapmaktan suçlu olduğunuzu bilmek için uygulamanız hakkında yeterli bilgimiz yok. Süpervizör verileri ne sıklıkla kullanılır? Bu bir israf gibi görünüyor, ama bilmiyoruz. Bunları ayrı tutarsanız, ne sıklıkta birlikte kullanıldıklarını görmek için sisteminizi izleyebilirsiniz. Daha sonra bunları tek bir çağrıda birleştirmeye karar verebilirsiniz. Aksi takdirde, bu büyük çağrı ile bir şişe boynu oluşturmaya başlarsanız, nerede sorun yaşamaya başlarsınız? Atlamayı neyin mantıklı olduğunu belirlemek zordur. Bu işleme daha fazla veri alanı eklenebilir.

Bunun ne kadarının db bellekten diske geldiğini bilmek ilginç olurdu. Departmanın adrese göre değişme olasılığının az çok olduğunu hissettirecek hiçbir şey yok.

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.