Tối ưu hóa các truy vấn Django ORM
Django ORM giúp việc làm việc với cơ sở dữ liệu trở nên dễ dàng. Nhưng nó cũng ẩn chứa một mối nguy hiểm. Nếu bạn truy xuất các đối tượng liên quan không đúng cách, bạn sẽ tạo ra vấn đề truy vấn N+1.
Điều này có nghĩa là nếu bạn lấy ra 100 bài viết, ứng dụng của bạn có thể phải chạy tới 101 truy vấn. Điều này sẽ khiến ứng dụng của bạn bị chậm lại đáng kể.
Hãy sử dụng hai công cụ sau để khắc phục:
- select_related
Sử dụng cái này cho ForeignKey và OneToOneField.
Nó sử dụng một lệnh SQL JOIN. Nó lấy dữ liệu liên quan chỉ trong một truy vấn duy nhất.
- Ví dụ: Một bài viết (Post) có một Tác giả (Author).
- Cách làm thông thường: 101 truy vấn cho 100 bài viết.
- Cách tối ưu: 1 truy vấn bằng cách sử dụng
.select_related("author").
- prefetch_related
Sử dụng cái này cho ManyToManyField và các ForeignKey ngược (reverse ForeignKeys).
Nó chạy các truy vấn riêng biệt và kết hợp chúng lại trong Python.
- Ví dụ: Một bài viết (Post) có nhiều Thẻ (Tags).
- Cách làm thông thường: 1 truy vấn cho các bài viết + 1 truy vấn cho thẻ của mỗi bài viết.
- Cách tối ưu: Tổng cộng 2 truy vấn bằng cách sử dụng
.prefetch_related("tags").
Mẹo chuyên nghiệp:
- Sử dụng đối tượng
Prefetchđể lọc dữ liệu liên quan trước khi nó đi vào vòng lặp của bạn. - Kết hợp chúng lại với nhau. Bạn có thể sử dụng cả hai trong cùng một
querysetđể lấy cả tác giả và thẻ cùng một lúc. - Tránh gọi
.filter()trên một mối quan hệ đã đượcprefetchbên trong một vòng lặp. Điều này sẽ bỏ qua bộ nhớ đệm (cache) và truy cập vào cơ sở dữ liệu một lần nữa. - Sử dụng
.only()kết hợp vớiselect_relatedđể chỉ lấy những cột mà bạn cần.
Tóm tắt:
ForeignKey/OneToOne: Sử dụngselect_related.ManyToMany/Reverse FK: Sử dụngprefetch_related.
Kiểm tra số lượng truy vấn của bạn bằng django-debug-toolbar để phát hiện sớm các vấn đề này.