N + 1 Problem
Tham khảo : https://viblo.asia/p/n-1-query-tinh-nang-hay-la-bug-maGK7WnMKj2
1. N + 1 Problem là gì ?
Hãy xét một ví dụ sau đây để thấy rõ :
Ví dụ: có hai quan hệ là book(id, name, author_id) và user(id, name) có quan hệ one-to-many với nhau tức là một người có thể viết nhiều sách. Yêu cầu truy xuất thông tin của các cuốn sách theo dạng JSON như sau: book { id name author { id name } }
Để thực hiện được cái này thông thường ta thực hiện câu truy vấn như sau :
BOOKS.all.each do
Book.user
end
Các câu lệnh sinh ra sẽ là :
SELECT "book".* from BOOKS
SELECT "author".* from USERS where "USERS".id = ?
SELECT "author".* from USERS where "USERS".id = ?
SELECT "author".* from USERS where "USERS".id = ?
Như vậy ta có thể thấy nó bao gồm hai giai đoạn :
- Giai đoạn 1: Chọn các cuốn sách từ sách
- Giai đoạn 2: Tìm các tác giả cho các cuốn sách đó
Giả sử có N = 3 quyển sách thì sẽ có bao nhiêu câu truy vấn ?
Đáp án là 4
1 câu truy vấn cho giai đoạn 1 và 3 câu truy vấn giai đoạn 2.
Như vậy N = 3 thì cần N + 1 câu truy vấn do đó bài toán này được gọi là N + 1 Problem
Đối với table có kích thước lớn chằng hạn như 1 000 000 thì số lượng câu truy vấn cần thực hiện sẽ là 1 000 001 như vậy sẽ ảnh hưởng rất lớn đến performance
Vậy làm thế nào để khắc phục vấn đề này ?
2. Cách giải quyết N + 1 Problem
2.1 Sử dụng Select in() query
SELECT "books".* FROM "BOOKS"
SELECT "authors".* FROM "USERS" WHERE "books"."author_id" IN (1, 2, 3)
Chỉ cần 2 bước đơn giản đầu tiên là truy vấn toàn bộ sách sau đó load các tác giả tương ứng.
2.2 Sử dụng Join
SELECT "books".* FROM "BOOKS" INNER JOIN "USERS" ON BOOKS.Author_id = USER.id
Như vậy Join chỉ tốn có 1 query mà thôi
Các loại JOIN

2.3 Vậy nên lựa chọn loại nào ?
Như vậy, không phải lúc nào gặp N + 1
cũng sẽ khử, nó còn phụ thuộc vào từng trường hợp cụ thể, khử được theo select in()
thì thì khử nó không thương tiếc, còn phải khử theo joins
thì nên chú ý tới độ lớn của bảng.
Last updated
Was this helpful?