Hiệu suất Eloquent: N+1 vấn đề truy vấn

Tram Ho

Hiệu suất hùng hồn thường là lý do chính khiến các dự án Laravel chậm. Một phần lớn trong số đó được gọi là “Vấn đề truy vấn N + 1”. Trong bài viết này, tôi sẽ đưa ra một vài ví dụ khác nhau về những điều cần lưu ý, bao gồm cả các trường hợp khi sự cố “ẩn” ở những vị trí không mong muốn trong mã.

Vấn đề truy vấn N+1 là gì

Tóm lại, đó là khi mã Laravel chạy quá nhiều truy vấn cơ sở dữ liệu. Nó xảy ra bởi vì Eloquent cho phép các nhà phát triển viết một cú pháp có thể đọc được với các mô hình mà không cần tìm hiểu sâu hơn về “điều kỳ diệu” đang diễn ra bên trong.

Đây không chỉ là vấn đề của Eloquent, hay thậm chí là của Laravel: nó nổi tiếng trong ngành công nghiệp phát triển. Tại sao gọi là “N+1”? Bởi vì, trong trường hợp Eloquent, nó truy vấn MỘT hàng từ cơ sở dữ liệu, sau đó thực hiện thêm một truy vấn cho MỖI bản ghi liên quan. Vì vậy, N truy vấn, cộng với chính bản ghi, tổng cộng là N+1.

Để giải quyết vấn đề này, chúng tôi cần truy vấn trước các bản ghi liên quan và Eloquent cho phép chúng tôi thực hiện điều đó một cách dễ dàng, với cái gọi là tải háo hức. Nhưng trước khi chúng ta đi đến các giải pháp, hãy thảo luận về các vấn đề

Trường hợp . Truy vấn N+1 “thông thường”. Cái này có thể được lấy trực tiếp từ tài liệu chính thức của Laravel:

chuyện gì xảy ra ở đây thế? Phần $book->author sẽ thực hiện thêm một truy vấn DB cho mỗi cuốn sách để lấy tác giả của nó.

Nhìn vào số lượng truy vấn. ví dụ1.png

Như bạn có thể thấy, đối với 20 cuốn sách, có 21 truy vấn, chính xác là N+1, trong đó N = 20.

Và vâng, bạn hiểu đúng: nếu bạn có 100 cuốn sách trong danh sách, bạn sẽ có 101 truy vấn tới DB. Hiệu suất khủng khiếp, mặc dù mã có vẻ “ngây thơ”, phải.

Cách khắc phục là tải trước mối quan hệ, ngay lập tức trong Bộ điều khiển, với tải háo hức mà tôi đã đề cập trước đó:

Kết quả tốt hơn nhiều – chỉ có 2 truy vấn: ví dụ1-2.png

Khi bạn sử dụng tải háo hức, Eloquent sẽ lấy tất cả các bản ghi vào mảng và khởi chạy MỘT truy vấn tới bảng DB liên quan, chuyển các ID đó từ mảng đó. Và sau đó, bất cứ khi nào bạn gọi $book->author, nó sẽ tải kết quả từ biến đã có sẵn trong bộ nhớ, không cần truy vấn lại cơ sở dữ liệu.

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo