Django ORM-da so'rovlarni optimallashtirish va tezlashtirish
Muallif: Javohir Abdullayev · · Django

Kirish: Nega Django ORM optimallashtirish muhim?
Django freymvorki o'zining tezkor ishlab chiqish imkoniyatlari va qulay ORM (Object-Relational Mapping) tizimi bilan mashhur. Biroq, loyiha kattalashgani va foydalanuvchilar soni ortgani sari, noto'g'ri yozilgan database so'rovlari backend serverini sekinlashtirishi mumkin. PyCoder.uz blogida bugun Django ORM orqali ma'lumotlar bazasi bilan ishlash samaradorligini oshirish va bazaga tushadigan yuklamani bir necha barobar kamaytirish usullarini ko'rib chiqamiz.
1. N+1 so'rovlar muammosi va uni hal qilish
N+1 muammosi - backend dasturchilar yo'l qo'yadigan eng ko'p tarqalgan xatolardan biridir. Bu holatda bitta obyektlar ro'yxatini olish uchun 1 ta so'rov, va har bir obyektning bog'liq ma'lumotlarini olish uchun yana N ta alohida so'rov ma'lumotlar bazasiga yuboriladi.
Misol uchun, blog postlari va ularning mualliflarini ko'rsatish talab etilsin. Oddiy usulda har bir post uchun muallif alohida bazadan chaqiriladi:
# Yomon amaliyot (N+1 muammosi):
posts = Post.objects.all()
for post in posts:
print(post.author.username) # Har safar yangi SQL so'rov bajariladiUshbu muammoni hal qilish uchun Django ikki xil maxsus metodni taqdim etadi: select_related va prefetch_related.
select_related dan foydalanish
select_related bitta-bitta (OneToOne) yoki ko'pga-bitta (ForeignKey) munosabatlar uchun ishlatiladi. U SQL darajasida JOIN operatoridan foydalanib, bog'liq ma'lumotlarni bitta so'rovda yuklab oladi.
# Yaxshi amaliyot:
posts = Post.objects.select_related('author').all()
for post in posts:
print(post.author.username) # Faqat 1 ta SQL so'rov bajariladiprefetch_related dan foydalanish
prefetch_related esa ko'pga-ko'p (ManyToMany) va bittaga-ko'p (Reverse ForeignKey) munosabatlar uchun mo'ljallangan. U har bir jadval uchun alohida so'rov yuboradi va Python xotirasida ularni birlashtiradi.
# Taglar bilan ishlashda:
posts = Post.objects.prefetch_related('tags').all()
for post in posts:
for tag in post.tags.all():
print(tag.name)2. Keraksiz ustunlarni yuklamaslik: only() va defer()
Odatda Post.objects.all() chaqirilganda, modeldagi barcha maydonlar, jumladan katta matnlar va rasmlar manzillari ham yuklanadi. Agar sizga faqat sarlavha va sana kerak bo'lsa, only() metodidan foydalaning.
# Faqat kerakli maydonlarni olish:
posts = Post.objects.only('title', 'created_at')Aksincha, agar ma'lum bir katta maydonni vaqtincha yuklamaslik kerak bo'lsa, defer() ishlatiladi:
# Matn maydonini chetlab o'tish:
posts = Post.objects.defer('content_html')3. Ma'lumot borligini tekshirish: exists() va count()
Ko'pgina dasturchilar modelda obyektlar borligini tekshirish uchun len(qs) yoki bool(qs) iboralaridan foydalanishadi. Bu juda katta xato, chunki u butun QuerySet-ni xotiraga yuklaydi.
- exists(): Ma'lumot bazada mavjudligini tezkor tekshiradi (SQL
EXISTSoperatori). - count(): Obyektlar sonini sanash uchun
COUNT(*)SQL so'rovini yuboradi.
# To'g'ri usul:
if Post.objects.filter(is_published=True).exists():
total = Post.objects.filter(is_published=True).count()4. Aggregatsiya va Annotatsiya imkoniyatlari
Ma'lumotlarni Python kodi ichida sikl aylantirib hisoblash o'rniga, SQL ma'lumotlar bazasining o'zida hisoblash sezilarli darajada tezroq ishlaydi. Buning uchun annotate() va aggregate() metodlaridan foydalaning.
from django.db.models import Count, Avg
# Har bir muallifning postlar sonini hisoblash:
authors = Author.objects.annotate(total_posts=Count('post'))
# Maqolalarning o'rtacha ko'rilish soni:
avg_views = Post.objects.aggregate(Avg('views_count'))5. Indekslash (Database Indexing)
Ma'lumotlar bazasida tez-tez filterlanadigan yoki saralanadigan maydonlarga indeks qo'yish unumdorlikni bir necha yuz barobar oshirishi mumkin. Django modelida db_index=True berish yoki Meta sinfida indexes ro'yxatini belgilash kifoya.
class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(unique=True, db_index=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
indexes = [
models.Index(fields=['created_at', 'is_published']),
]6. Profilallash vositalari: Django Debug Toolbar va Silk
Kod qanchalik sekin ishlayotganini va nechta SQL so'rov bajarilayotganini aniqlash uchun quyidagi vositalardan foydalaning:
- Django Debug Toolbar: Lokal muhitda har bir sahifada nechtadan SQL so'rovi bajarilganini va ularning bajarilish vaqtini ko'rsatib beradi.
- django-silk: Production va staging muhitlarida so'rovlarni profiling qilish hamda sekin ishlayotgan API endpointlarni tahlil qilish uchun ajoyib vosita.
Xulosa
Django ORM judayam kuchli vosita, lekin undan to'g'ri foydalanish backend dasturchining asosiy ko'nikmalaridan biridir. Yuqorida keltirilgan select_related, prefetch_related, only, indekslash va profilallash usullarini amalda qo'llash orqali siz veb-ilovangiz tezligini sezilarli darajada oshirishingiz mumkin. PyCoder.uz platformasida backend va Django bo'yicha yangi va foydali darsliklarni kuzatib borishda davom eting!
Teglar: #Django #Python #Backend #ORM optimallashtirish #PyCoder