Trong Rails, ActiveRecord cung cấp nhiều loại join khác nhau để kết hợp các bảng trong cơ sở dữ liệu. Dưới đây là các loại join phổ biến và sự khác biệt giữa chúng:
1. joins
- Mục đích: Thực hiện INNER JOIN giữa các bảng.
- Cách hoạt động: Chỉ trả về các bản ghi có bản ghi tương ứng trong cả hai bảng.
- Khi nào sử dụng: Khi bạn chỉ muốn lấy các bản ghi có liên kết trong cả hai bảng.
Ví dụ:
Offer.joins(:delivery_packages)
SQL tương ứng:
SELECT offers.* FROM offers
INNER JOIN delivery_packages ON delivery_packages.offer_id = offers.id
2. left_joins
- Mục đích: Thực hiện LEFT OUTER JOIN giữa các bảng.
- Cách hoạt động: Trả về tất cả các bản ghi từ bảng chính và các bản ghi tương ứng từ bảng liên quan nếu chúng tồn tại.
- Khi nào sử dụng: Khi bạn muốn lấy tất cả các bản ghi từ bảng chính và chỉ lấy các bản ghi từ bảng liên quan nếu chúng tồn tại.
Ví dụ:
Offer.left_joins(:delivery_packages)
SQL tương ứng:
SELECT offers.* FROM offers
LEFT OUTER JOIN delivery_packages ON delivery_packages.offer_id = offers.id
3. includes
- Mục đích: Tải trước các bản ghi liên quan để tránh vấn đề N+1 query.
- Cách hoạt động: Thực hiện một truy vấn SQL duy nhất với LEFT OUTER JOIN hoặc nhiều truy vấn riêng biệt để tải trước các bản ghi liên quan.
- Khi nào sử dụng: Khi bạn muốn tránh vấn đề N+1 query và cần tải trước các bản ghi liên quan để sử dụng sau này trong mã.
Ví dụ:
Offer.includes(:delivery_packages)
SQL tương ứng (có thể là một trong hai):
SELECT offers.* FROM offers
LEFT OUTER JOIN delivery_packages ON delivery_packages.offer_id = offers.id
hoặc
SELECT offers.* FROM offers;
SELECT delivery_packages.* FROM delivery_packages WHERE delivery_packages.offer_id IN (1, 2, 3, ...);
4. eager_load
- Mục đích: Tải trước các bản ghi liên quan bằng cách sử dụng một truy vấn SQL duy nhất với LEFT OUTER JOIN.
- Cách hoạt động: Tạo ra một truy vấn SQL với LEFT OUTER JOIN và tải trước các bản ghi liên quan, sau đó ActiveRecord sẽ ánh xạ các bản ghi liên quan vào các đối tượng tương ứng trong bộ nhớ.
- Khi nào sử dụng: Khi bạn muốn tránh vấn đề N+1 query và cần tải trước các bản ghi liên quan để sử dụng sau này trong mã.
Ví dụ:
Offer.eager_load(:delivery_packages)
SQL tương ứng:
SELECT offers.*, delivery_packages.* FROM offers
LEFT OUTER JOIN delivery_packages ON delivery_packages.offer_id = offers.id
5. preload
- Mục đích: Tải trước các bản ghi liên quan bằng cách sử dụng nhiều truy vấn riêng biệt.
- Cách hoạt động: Thực hiện một truy vấn để lấy các bản ghi từ bảng chính và một hoặc nhiều truy vấn riêng biệt để lấy các bản ghi liên quan.
- Khi nào sử dụng: Khi bạn muốn tránh vấn đề N+1 query và không cần kết hợp các bảng trong một truy vấn SQL duy nhất.
Ví dụ:
Offer.preload(:delivery_packages)
SQL tương ứng:
SELECT offers.* FROM offers;
SELECT delivery_packages.* FROM delivery_packages WHERE delivery_packages.offer_id IN (1, 2, 3, ...);
So sánh
joins
: Thực hiện INNER JOIN, chỉ trả về các bản ghi có liên kết trong cả hai bảng.left_joins
: Thực hiện LEFT OUTER JOIN, trả về tất cả các bản ghi từ bảng chính và các bản ghi tương ứng từ bảng liên quan nếu chúng tồn tại.includes
: Tải trước các bản ghi liên quan để tránh vấn đề N+1 query, có thể sử dụng LEFT OUTER JOIN hoặc nhiều truy vấn riêng biệt.eager_load
: Tải trước các bản ghi liên quan bằng cách sử dụng một truy vấn SQL duy nhất với LEFT OUTER JOIN.preload
: Tải trước các bản ghi liên quan bằng cách sử dụng nhiều truy vấn riêng biệt.
Kết luận
- Sử dụng
joins
khi bạn chỉ muốn lấy các bản ghi có liên kết trong cả hai bảng. - Sử dụng
left_joins
khi bạn muốn lấy tất cả các bản ghi từ bảng chính và chỉ lấy các bản ghi từ bảng liên quan nếu chúng tồn tại. - Sử dụng
includes
,eager_load
, hoặcpreload
khi bạn muốn tránh vấn đề N+1 query và cần tải trước các bản ghi liên quan để sử dụng sau này trong mã.