Ana içeriğe geç

N+1 Sorgu Sorunu

İngilizcesi
N+1 Query Problem
Okunuşu
en plas van kuiri problım

Günlük kullanımda iki ad da yaygın.

Güncellendi 2 dk okuma

Bu sayfayı paylaşın

Bağlantıyı gönderin, tanımı bağlantısıyla birlikte alıntılayın ya da kendi sitenizde bir kart olarak gösterin.

https://softwaredictionary.org/tr/terimler/n-plus-one-query

Kısaca

N+1 sorgu sorunu, kodun bir listeyi tek sorguyla yükleyip sonra her öğe için bir sorgu daha çalıştırdığı, hepsini birden getirmediği bir performans hatasıdır.

N+1 sorgu sorunu nedir?

N+1 sorgu sorunu, kod N kayıttan oluşan bir listeyi tek bir sorguyla getirip ardından üzerlerinde dolaşarak her kaydın ilişkili verisi için ayrı bir sorgu çalıştırdığında ortaya çıkar. Bu toplamda 1 + N sorgu eder. 10 kayıtla neredeyse fark edilmez, ancak 1.000 kayıtla tek bir sayfa yüklemesi veritabanına 1.001 sorgu gönderir.

Sorun çoğu zaman bir ORM'in lazy loading'i tarafından gizlenir: bir döngü içinde post.author okumak basit bir özellik erişimi gibi görünür, ancak her seferinde sessizce bir sorgu çalıştırır. Her sorgu tek başına küçük ve hızlıdır, ancak ağ gidiş-dönüşleri ve sorgu başına ek yük birleşince yavaş bir sayfa ortaya çıkar. Çözüm, ilişkili veriyi sabit ve az sayıda sorguyla getirmektir: ORM'de eager loading, tek bir JOIN ya da WHERE id IN (...) ile tek bir toplu sorgu kullanarak. GraphQL sunucuları bunu genellikle ID'leri toplayıp birlikte yükleyen, çoğu zaman data loader denen bir toplu işleme katmanıyla çözer.

Bu, alışveriş listenizdeki her ürün için markete bir kez gitmeye, hepsini tek seferde almak yerine, benzer. Sorunu veritabanı sorgu günlüklerinde, ORM hata ayıklama çıktısında ya da istek başına düzinelerce kez tekrarlanan aynı sorgu biçimini gösteren istek izlerinde (trace) fark edebilirsiniz; bazı ekipler bir endpoint belirli bir sorgu sayısını aştığında başarısız olan testler de ekler.

N+1 sorunu yavaş bir sorgudan farklıdır. Yavaş sorgu, bir indeks ya da yeniden yazımla çoğu zaman düzeltilebilen tek bir pahalı ifadedir; N+1 ise her biri kendi başına iyi görünen çok sayıda ucuz ifadedir, bu yüzden indeks eklemek yardımcı olmaz. Her şeyi eager loading ile yüklemek de her zaman cevap değildir; çünkü bir sayfanın hiç kullanmadığı ilişkili veriyi yüklemek bellek ve zaman israfıdır.

Bir bakışta

Üç gönderiyi yazarlarıyla listelemek. N+1 yolunda gönderiler için bir sorgu, ardından her gönderinin yazarı için bir sorgu daha çalışır: veritabanına dört gidiş-dönüş. Düzeltilmiş yolda gönderiler ve yazarları bir join ile tek bir sorguda birlikte gelir.N + 1 sorguliste için 1, sonra gönderi başına 1SELECT * FROM posts LIMIT 3SELECT * FROM users WHERE id = 1SELECT * FROM users WHERE id = 2SELECT * FROM users WHERE id = 34 gidiş-dönüşTek sorgugönderiler ve yazarlar birlikteSELECT posts.*, users.name FROM postsJOIN users ON users.id = posts.author_idLIMIT 31 gidiş-dönüşÇoğu zaman bir ORM döngüsünde gizlidir: her gönderi için post.author
3 gönderide 4 sorgu; 1.000 gönderide 1.001. İlişkili satırları birlikte çekmek, liste ne kadar uzun olursa olsun sayıyı bir ya da ikide tutar.

Önemli noktalar

  • N+1, bir liste için bir sorgu artı listedeki her öğe için bir sorgu demektir.
  • ORM lazy loading'i en yaygın gizli nedendir.
  • Her sorgu hızlıdır, ancak liste büyüdükçe gidiş-dönüşler birikir.
  • Eager loading, bir JOIN ya da toplu bir IN sorgusuyla düzeltin.
  • İndeksler N+1'i çözmez; çünkü sorun sorgu sayısıdır.

Örnek

N+1 sorgular ve toplu bir çözümjavascript
// N+1: 1 query for the posts, then 1 query per post for its author
const posts = await db.query("SELECT * FROM posts LIMIT 50");
for (const post of posts) {
  const rows = await db.query("SELECT * FROM users WHERE id = ?", [post.author_id]);
  post.author = rows[0];
}

// Fix: load all the authors in one extra query (2 queries in total)
const ids = posts.map((p) => p.author_id);
const authors = await db.query("SELECT * FROM users WHERE id IN (?)", [ids]);
const byId = new Map(authors.map((a) => [a.id, a]));
for (const post of posts) post.author = byId.get(post.author_id);

Sık sorulan sorular

N+1 sorguları nasıl tespit ederim?

ORM'inizde ya da veritabanında sorgu günlüğünü açın ve tek bir istek sırasında farklı ID'lerle tekrarlanan aynı sorguyu arayın. İzleme ve performans takip araçları ile bazı ORM eklentileri örüntüyü otomatik olarak işaretleyebilir.

ORM kullanmak N+1 sorununa yol açar mı?

ORM tek başına buna yol açmaz, ancak lazy loading bunu yanlışlıkla yazmayı çok kolaylaştırır. Çoğu ORM, ilişkili kayıtları baştan yüklemek için include ya da prefetch gibi eager loading seçenekleri sunar.

JOIN her zaman N+1 sorgulardan daha mı iyidir?

Genellikle, ama her zaman değil. Bir birleştirme üst veriyi birçok satır boyunca çoğaltabilir; bu yüzden büyük bire-çok ilişkilerde biri üst kayıtlar, diğeri alt kayıtlar için toplu iki sorgu çoğu zaman daha temiz ve aynı derecede hızlıdır.

İlgili sayfalar

Bu sayfada bir hata ya da eksik mi gördünüz?Düzeltme önerin

Daha fazla

Ayarlar