Chuyển đến nội dung chính

レッスン 18: パフォーマンスの最適化

Django デバッグ ツールバー、クエリの最適化。 N+1 クエリの問題、select_関連/プリフェッチ関連。データベースのインデックス作成、クエリプロファイリング。接続プーリング、リードレプリカ。

💻 プログラミング — レッスン 18 レッスン 18: パフォーマンスの最適化

Django: 基本から上級まで

パート 5: テスト、展開、実稼働

xdev.asia

1. Django デバッグツールバー

pip install django-debug-toolbar
# settings.py (development only)
INSTALLED_APPS = [..., 'debug_toolbar']
MIDDLEWARE = ['debug_toolbar.middleware.DebugToolbarMiddleware', ...]
INTERNAL_IPS = ['127.0.0.1']

2. クエリの最適化

# N+1 Problem
# SAI — N+1 queries
products = Product.objects.all()
for p in products:
    print(p.category.name)  # Mỗi iteration = 1 query

# ĐÚNG — select_related (ForeignKey, OneToOne)
products = Product.objects.select_related('category', 'brand').all()

# ĐÚNG — prefetch_related (ManyToMany, reverse FK)
products = Product.objects.prefetch_related('tags', 'images').all()

# Prefetch với custom queryset
from django.db.models import Prefetch

products = Product.objects.prefetch_related(
    Prefetch(
        'reviews',
        queryset=Review.objects.filter(rating__gte=4).select_related('user'),
        to_attr='top_reviews',
    )
)

3. 集計と注釈付け

from django.db.models import Count, Avg, Sum, F, Q

# Thay vì loop tính toán
products = Product.objects.annotate(
    review_count=Count('reviews'),
    avg_rating=Avg('reviews__rating'),
    revenue=F('price') * F('sold_count'),
).filter(
    review_count__gte=5,
    avg_rating__gte=4.0,
).order_by('-revenue')

# Conditional aggregation
stats = Product.objects.aggregate(
    total=Count('id'),
    active=Count('id', filter=Q(is_active=True)),
    avg_price=Avg('price'),
)

4. データベースのインデックス作成

class Product(models.Model):
    name = models.CharField(max_length=255, db_index=True)
    slug = models.SlugField(unique=True)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        indexes = [
            models.Index(fields=['category', '-created_at']),
            models.Index(fields=['price', 'is_active']),
            models.Index(
                fields=['name'],
                condition=Q(is_active=True),
                name='active_product_name_idx',
            ),
        ]

5. 接続プーリングとリードレプリカ

# pip install django-db-connection-pool
DATABASES = {
    'default': {
        'ENGINE': 'dj_db_conn_pool.backends.postgresql',
        'POOL_OPTIONS': {
            'POOL_SIZE': 10,
            'MAX_OVERFLOW': 5,
        },
    },
    'replica': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydb',
        'HOST': 'replica.db.example.com',
    },
}

class PrimaryReplicaRouter:
    def db_for_read(self, model, **hints):
        return 'replica'

    def db_for_write(self, model, **hints):
        return 'default'

DATABASE_ROUTERS = ['config.routers.PrimaryReplicaRouter']

次の記事: Django 用の Docker と CI/CD。