Vụ án chỉ mục cơ sở dữ liệu bị mất
By ducpm, at: 16:25 Ngày 29 tháng 10 năm 2025
Thời gian đọc ước tính: __READING_TIME__ phút
Giới thiệu
Ứng dụng Django của bạn chạy mượt mà trong quá trình phát triển. Các truy vấn trả về ngay lập tức. Nhưng trong môi trường sản xuất, mọi thứ chậm lại đáng kể. Trang web mất vài giây để tải, người dùng phàn nàn và sử dụng CPU tăng đột biến.
Nguyên nhân? Một chỉ mục cơ sở dữ liệu bị thiếu - một kẻ giết người hiệu năng vô hình ẩn giấu cho đến khi lưu lượng truy cập tăng lên. Tại Glinteco, chúng tôi đã thấy điều này vô số lần: các ứng dụng có số lượng người dùng tăng nhưng thiết kế cơ sở dữ liệu không.
Bối cảnh: Truy vấn chậm
Một truy vấn đơn giản như thế này chạy trong vài mili giây trong môi trường phát triển:
BlogPost.objects.filter(author_id=42).order_by('-created_at')
Nhưng trong môi trường sản xuất, với hàng triệu hàng, cùng một truy vấn mất nhiều giây. Cơ sở dữ liệu quét toàn bộ bảng thay vì sử dụng lối tắt.
Bằng chứng bị thiếu trong hiện trường vụ án này? Một chỉ mục.
Vấn đề xảy ra như thế nào
-
Bộ dữ liệu phát triển nhỏ
-
Các cơ sở dữ liệu cục bộ chỉ có vài trăm hàng. Hiệu năng trông ổn
-
-
Tăng trưởng nhanh chóng trong sản xuất
-
Khi số lượng bản ghi tăng lên hàng triệu, các truy vấn chậm lại theo cấp số nhân
-
-
Không có chiến lược chỉ mục
-
Các nhà phát triển dựa vào các giá trị mặc định, quên tối ưu hóa các cột thường được sử dụng trong bộ lọc hoặc nối
-
-
Sai lầm về việc lập chỉ mục quá mức
-
Ngược lại, quá nhiều chỉ mục có thể làm chậm quá trình ghi và lãng phí dung lượng lưu trữ
-
Gỡ lỗi tắc nghẽn
Để phát hiện chỉ mục bị thiếu, các nhà phát triển sử dụng các công cụ cơ sở dữ liệu:
-
EXPLAIN / EXPLAIN ANALYZE trong Postgres hoặc MySQL để xem kế hoạch truy vấn
-
Django Debug Toolbar để phát hiện các truy vấn chậm
-
Các công cụ giám sát như New Relic hoặc Datadog để đo lường hiệu năng truy vấn
Tài liệu của PostgreSQL cung cấp hướng dẫn chi tiết về việc đọc kế hoạch truy vấn.
Khắc phục
Thêm chỉ mục vào các bộ lọc phổ biến
Ví dụ
CREATE INDEX idx_blogpost_author ON blogpost (author_id);
Sử dụng db_index=True của Django
author = models.ForeignKey(User, on_delete=models.CASCADE, db_index=True)
Tận dụng Chỉ mục Hợp thành
Đối với các truy vấn lọc trên nhiều trường.
BlogPost.objects.filter(author_id=42, created_at__gte="2025-01-01")
Nếu không có chỉ mục, cơ sở dữ liệu sẽ quét toàn bộ bảng blogpost. Với chỉ mục hợp thành trên (author_id, created_at), cơ sở dữ liệu có thể nhảy trực tiếp đến tập hợp con chính xác.
Giải pháp
class BlogPost(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
indexes = [
models.Index(fields=['author', 'created_at']),
]
Thường xuyên kiểm tra các truy vấn
Chạy phân tích truy vấn trong môi trường staging với khối lượng dữ liệu thực tế.
Tránh lập chỉ mục quá mức
Mỗi chỉ mục làm tăng tốc độ đọc nhưng làm chậm tốc độ ghi. Cần đạt được sự cân bằng.
Thông tin thêm có thể được tìm thấy tại đây: https://testdriven.io/blog/django-db-indexing/
Bài học kinh nghiệm
Chỉ mục cơ sở dữ liệu vô hình khi bị thiếu cho đến khi chúng làm hệ thống của bạn ngừng hoạt động. Trường hợp Chỉ mục Bị Thiếu là lời nhắc nhở rằng hiệu năng không chỉ là về mã, mà còn về thiết kế dữ liệu ở quy mô lớn.
Tại Glinteco, chúng tôi giúp khách hàng trên khắp các ngành thiết kế các hệ thống Django và cơ sở dữ liệu có khả năng mở rộng. Cho dù đó là thêm chỉ mục phù hợp, điều chỉnh truy vấn hay xây dựng kế hoạch tăng trưởng dài hạn, chúng tôi đảm bảo ứng dụng của bạn luôn nhanh chóng khi mở rộng.
Nếu ứng dụng của bạn cảm thấy chậm chạp và bạn không thể tìm ra nguyên nhân, đó có thể chỉ là một chỉ mục bị thiếu và chúng tôi biết cách tìm ra nó.