Darslik · 2025-08-03 · ~1 daqiqa o‘qiladi · o'rta
Django ORM'da N+1 muammosi va uni yechish
Mundarija
Django ORM qulay — SQL yozmasdan ma'lumot olasiz. Lekin bu qulaylik yashirin narx bilan keladi: agar ehtiyot bo‘lmasangiz, ORM bitta sahifada yuzlab so‘rov yuborishi mumkin. Bu N+1 muammosi.
Muammo qanday paydo bo‘ladi#
Faraz qilaylik, maqolalar va ularning mualliflarini ko‘rsatyapmiz:
posts = Post.objects.all() # 1 so‘rov
for post in posts:
print(post.author.name) # HAR post uchun +1 so‘rov!
100 ta maqola bo‘lsa — 101 so‘rov: bitta maqolalar uchun, yuzta muallif uchun. Bazaga bunday ko‘p murojaat sahifani sezilarli sekinlashtiradi.
Yechim: select_related#
Bir-biriga (ForeignKey) bog‘langan ma'lumot uchun select_related — u
JOIN ishlatib, hammasini bitta so‘rovda oladi:
posts = Post.objects.select_related("author") # 1 so‘rov, JOIN bilan
for post in posts:
print(post.author.name) # qo‘shimcha so‘rov yo‘q
101 so‘rov → 1 so‘rov.
prefetch_related — ko‘plik bog‘lanishlar uchun#
ManyToMany yoki teskari ForeignKey (masalan, maqolaning teglari) uchun
prefetch_related ishlating:
posts = Post.objects.prefetch_related("tags")
for post in posts:
print([tag.name for tag in post.tags.all()]) # oldindan yuklangan
U ikki so‘rov yuboradi (maqolalar + teglar) va Python'da birlashtiradi — har maqola uchun alohida so‘rov o‘rniga.
Muammoni qanday aniqlash#
- django-debug-toolbar — sahifadagi so‘rovlar sonini ko‘rsatadi. Agar son ma'lumot bilan birga o‘ssa — N+1 bor.
- Test'da
assertNumQueries()bilan so‘rovlar sonini tekshiring.
Qoida#
Sikl ichida bog‘langan ob'ektga murojaat qilsangiz — ehtimol N+1 bor.
select_related (bitta ob'ekt) yoki prefetch_related (ko‘p ob'ekt) bilan oldindan yuklang.
Bu Django loyihalarida eng ko‘p uchraydigan performance muammosi.