Asosiy kontentga o‘tish

Maqolalar

Darslik · 2025-08-03 · ~1 daqiqa o‘qiladi · o'rta

Django ORM'da N+1 muammosi va uni yechish

#django #backend #performance

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.

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.

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.