آنچه در این مقاله میخوانید [پنهانسازی]
تفاوت select_related و prefetch_related در Django به نحوه دریافت دادههای مرتبط از دیتابیس مربوط میشود. هر دو برای کاهش تعداد Query ها و افزایش Performance استفاده میشوند اما روش کار آنها کاملا متفاوت است. اگر این دو قابلیت اشتباه استفاده شوند، نه تنها سرعت پروژه بهتر نمیشود بلکه ممکن است Query ها سنگینتر و مصرف RAM بیشتر شود.
سرفصل های مقاله
- چرا باید از select_related و prefetch_related استفاده کنیم؟
- select_related در Django چیست؟
- خروجی Query در select_related
- مزیت select_related
- prefetch_related در Django چیست؟
- چرا prefetch_related از JOIN استفاده نمیکند؟
- تفاوت اصلی select_related و prefetch_related
- چه زمانی باید از select_related استفاده کنیم؟
- چه زمانی باید از prefetch_related استفاده کنیم؟
- آیا میتوان هر دو را همزمان استفاده کرد؟
- اشتباهات رایج برنامه نویسان Django
- استفاده از select_related روی ManyToMany
- استفاده زیاد از prefetch_related
- فراموش کردن Optimization
- چگونه تعداد Query ها را بررسی کنیم؟
- استفاده از Django Debug Toolbar
- بررسی Query ها در Console
- تاثیر select_related و prefetch_related روی Performance
- چه زمانی استفاده نکردن بهتر است؟
- روش اصولی استفاده در پروژه واقعی
- فقط Relationship های لازم را Load کنید
- Query ها را Monitor کنید
- API ها را تست کنید
- از ترکیب این دو قابلیت درست استفاده کنید
- جمع بندی
یکی از رایجترین مشکلات پروژههای Django اجرای تعداد زیاد Query است.
مثلا:
posts = Post.objects.all()
for post in posts:
print(post.author.username)
در ظاهر فقط یک Query اجرا شده اما Django برای هر Author یک Query جدا میزند.
اگر 100 پست وجود داشته باشد:
- 1 Query برای Post ها
- 100 Query برای Author ها
اجرا میشود.
به این مشکل N+1 Query گفته می شود.
select_related برای Relationship های:
- ForeignKey
- OneToOne
استفاده میشود.
این قابلیت با استفاده از SQL JOIN اطلاعات مرتبط را در همان Query اصلی دریافت میکند.
مثلا:
posts = Post.objects.select_related('author')
در این حالت Django اطلاعات Post و Author را با یک Query دریافت میکند.
پشت صحنه چیزی شبیه این اتفاق میافتد:
SELECT * FROM post
JOIN author
ON post.author_id = author.id
یعنی اطلاعات همزمان خوانده میشوند.
مزیت اصلی:
- کاهش تعداد Query
- افزایش سرعت پروژه
- کاهش فشار روی دیتابیس
است.
مخصوصا زمانی که:
- تعداد داده زیاد باشد
- ForeignKey زیاد استفاده شود
این قابلیت بسیار مهم میشود.
prefetch_related برای:
- ManyToMany
- Reverse ForeignKey
استفاده میشود.
برخلاف select_related، این قابلیت JOIN انجام نمی دهد.
بلکه:
- Query اصلی را اجرا میکند
- بعد Query های جداگانه اجرا میکند
- نتیجه را داخل Python ترکیب میکند
مثلا:
products = Product.objects.prefetch_related('categories')
در Relationship های ManyToMany استفاده از JOIN می تواند دادههای تکراری بسیار زیادی تولید کند.
برای همین Django:
- Query ها را جدا اجرا میکند
- بعد داده ها را ترکیب میکند
این روش در بسیاری از شرایط سریع تر و بهینهتر است.
مهمترین تفاوت این است:
- select_related:
- JOIN میزند
- فقط برای ForeignKey و OneToOne
- یک Query اجرا میکند
- prefetch_related:
- Query جدا اجرا میکند
- برای ManyToMany و Reverse Relation
- دادهها را داخل Python ترکیب میکند
وقتی Relationship از نوع:
- ForeignKey
- OneToOne
باشد.
مثلا:
class Post(models.Model):
author = models.ForeignKey(User)
اینجا بهترین گزینه:
Post.objects.select_related('author')
است.
وقتی Relationship از نوع:
- ManyToMany
- Reverse ForeignKey
باشد.
مثلا:
class Product(models.Model):
categories = models.ManyToManyField(Category)
اینجا باید از:
Product.objects.prefetch_related('categories')
استفاده شود.
آیا میتوان هر دو را همزمان استفاده کرد؟
بله.
مثلا:
Post.objects.select_related(
'author'
).prefetch_related(
'tags'
)
اینجا:
- author با JOIN دریافت میشود
- tags با Query جداگانه
اشتباهات رایج برنامه نویسان Django
مثلا:
Product.objects.select_related('categories')
این اشتباه است.
چون select_related برای ManyToMany طراحی نشده است.
بعضی پروژهها همه Relationship ها را Prefetch میکنند.
نتیجه:
- RAM زیاد مصرف میشود
- Query ها سنگین میشوند
- سرعت افت میکند
نباید بدون نیاز از Prefetch استفاده شود.
فراموش کردن Optimization
خیلی از پروژهها اصلا از این قابلیت ها استفاده نمیکنند.
در نتیجه:
- تعداد Query ها بالا میرود
- Performance افت میکند
- سرور تحت فشار قرار میگیرد
چگونه تعداد Query ها را بررسی کنیم؟
استفاده از Django Debug Toolbar
این ابزار یکی از بهترین روشها برای تحلیل Query هاست.
نصب:
pip install django-debug-toolbar
این ابزار نشان میدهد:
- چند Query اجرا شده
- زمان اجرای هر Query
- Query های کند
چیست.
بررسی Query ها در Console
مثلا:
print(connection.queries)
اگر تعداد Query زیاد باشد، معمولا مشکل از Relationship هاست.
در پروژههای واقعی این دو قابلیت میتوانند:
- تعداد Query ها را شدیدا کم کنند
- زمان پاسخ API را کاهش دهند
- فشار روی Database را کمتر کنند
مخصوصا در:
- API ها
- پنل ادمین
- Dashboard ها
خیلی مهم هستند.
چه زمانی استفاده نکردن بهتر است؟
اگر داده مرتبط استفاده نمیشود، نباید:
- select_related
- prefetch_related
اضافه شوند.
چون:
- حافظه بیشتری مصرف میشود
- Query سنگین تر میشود
- Performance ممکن است بدتر شود
روش اصولی استفاده در پروژه واقعی
فقط Relationship های لازم را Load کنید
نباید همه چیز را یکجا دریافت کنید.
مثلا:
Post.objects.select_related('author')
بهتر از دریافت دهها Relationship اضافی است.
Query ها را Monitor کنید
خیلی از مشکلات Performance فقط بعد از بزرگ شدن پروژه مشخص میشوند.
Monitoring منظم بسیار مهم است.
API ها را تست کنید
گاهی Query در Development سریع است اما در Production کند میشود.
باید:
- داده واقعی
- حجم واقعی
- تعداد کاربر واقعی
تست شوند.
از ترکیب این دو قابلیت درست استفاده کنید
بعضی پروژهها همزمان به:
- ForeignKey
- ManyToMany
نیاز دارند.
در این شرایط ترکیب select_related و prefetch_related بهترین انتخاب است.
جمع بندی
تفاوت select_related و prefetch_related در Django به نحوه دریافت دادههای مرتبط از دیتابیس مربوط میشود. select_related با JOIN و یک Query کار میکند و برای ForeignKey مناسب است، اما prefetch_related Query جدا اجرا میکند و برای ManyToMany کاربرد دارد. استفاده درست از این دو قابلیت میتواند Performance پروژه را به شکل محسوسی بهتر کند و جلوی مشکل N+1 Query را بگیرد.





