Mở đầu
Tập này dạy bạn đo hiệu năng thật trước khi tối ưu: bật slow query log của PostgreSQL, gắn django-silk để soi từng request, đọc EXPLAIN để biết query nào quét toàn bảng, rồi thêm index đúng chỗ. Nối tiếp tập 11, nơi ứng dụng quản lý chi tiêu đã được khóa chặt về bảo mật, giờ là lúc xem nó chạy nhanh hay chậm dưới tải thật.
1. Bật slow query log của PostgreSQL
PostgreSQL có thể ghi lại mọi query chạy chậm hơn một ngưỡng bạn chọn. Đặt log_min_duration_statement = 1000 trong postgresql.conf để ghi mọi query chạy trên một giây, rồi xem log để biết câu nào lặp lại nhiều nhất trong ứng dụng quản lý chi tiêu — thường là trang danh sách giao dịch theo tháng.
# postgresql.conflog_min_duration_statement = 1000 # ms: ghi mọi query chạy trên 1 giâylog_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d '
2. Gắn django-silk để soi từng request
Slow query log cho biết câu nào chậm, nhưng django-silk cho biết request nào sinh ra nó. Cài silk, thêm middleware và URL, rồi mở /silk/ để xem từng request kèm thời gian từng query, số query trùng lặp và cả profile chi tiết của view.
# config/settings/prod.pyINSTALLED_APPS += ["silk"]MIDDLEWARE += ["silk.middleware.SilkyMiddleware"]SILKY_PYTHON_PROFILER = True
# config/urls.pyurlpatterns += [path("silk/", include("silk.urls", namespace="silk"))]
3. Đọc EXPLAIN trước khi sửa
Khi đã có query chậm, chạy EXPLAIN ANALYZE trong psql để xem kế hoạch thực thi: Seq Scan trên bảng expenses_transaction nghĩa là PostgreSQL đọc hết bảng, còn Index Scan nghĩa là nó dùng index. Chú ý cột Actual Time và Rows Removed by Filter — filter loại bỏ càng nhiều hàng thì càng nên có index cho điều kiện đó.
EXPLAIN ANALYZESELECT * FROM expenses_transactionWHERE user_id = 1 AND date >= '2026-11-01'ORDER BY date DESC;
4. Thêm index đúng chỗ
Đừng thêm index cho mọi cột: mỗi index làm INSERT chậm đi và tốn dung lượng. Thêm index cho cột hay dùng trong WHERE và ORDER BY, ví dụ cặp (user, date) trên bảng giao dịch — và dùng index kết hợp thay vì hai index rời khi query lọc cả hai cột cùng lúc.
# expenses/models.pyclass Transaction(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) date = models.DateField() amount = models.DecimalField(max_digits=12, decimal_places=2) class Meta: indexes = [ models.Index(fields=["user", "date"]), ]
5. Đo lại và giữ thói quen profiling
Sau khi thêm index, chạy lại EXPLAIN ANALYZE để chắc chắn query đã dùng Index Scan, rồi so sánh thời gian trước và sau. Ghi số liệu vào runbook của dự án: profiling không phải việc làm một lần, mà là thói quen mỗi khi thêm tính năng mới hay dữ liệu tăng gấp đôi.
Áp dụng vào dự án của bạn
Áp dụng ngay tối nay: bật slow query log với ngưỡng một giây, cài django-silk lên staging, mở trang danh sách giao dịch theo tháng rồi xem /silk/ để tìm query chậm nhất. Chạy EXPLAIN ANALYZE cho nó, thêm index cho cột lọc, đo lại và ghi kết quả vào runbook.
Bài viết liên quan
- Django vận hành production #11: Security checklist — ALLOWED_HOSTS, HTTPS/HSTS, CSRF/CORS, các SECURE_* và django-axes
- Django vận hành production #10: Celery trên production — worker, beat, Flower, systemd và retry
- Django vận hành production #9: Cache với Redis — cache framework, pattern invalidation, tránh cache sai dữ liệu
Câu hỏi thường gặp
django-silk có làm chậm production không?
Có, một chút: silk ghi mọi request và query vào database, nên chỉ bật trên staging hoặc bật tạm trên production khi cần điều tra rồi tắt. Tuyệt đối không để /silk/ mở công khai — bảo vệ bằng đăng nhập hoặc IP allowlist.
EXPLAIN và EXPLAIN ANALYZE khác nhau thế nào?
EXPLAIN chỉ cho thấy kế hoạch dự kiến mà không chạy query, còn EXPLAIN ANALYZE chạy thật rồi báo thời gian thực tế từng bước. Dùng ANALYZE để chẩn đoán, nhưng đừng chạy nó trên query UPDATE hay DELETE trên production vì nó thực thi thật.
Thêm index mà query vẫn chậm thì sao?
Kiểm tra lại EXPLAIN: có thể query vẫn quét toàn bảng vì điều kiện WHERE dùng hàm trên cột, ví dụ DATE(created_at), khiến index không dùng được. Khi đó viết lại query để so sánh trực tiếp trên cột, hoặc tạo index biểu thức nếu thật sự cần.
Nguồn tham khảo
- Django Documentation — Database optimization: https://docs.djangoproject.com/en/6.0/topics/db/optimization/
- django-silk Documentation: https://github.com/jazzband/django-silk
- PostgreSQL Documentation — Using EXPLAIN: https://www.postgresql.org/docs/current/using-explain.html
