Xin chào, lại là mình - Đức Phúc, anh chàng hơn 6 năm trong nghề vẫn nghèo technical nhưng thích viết Blog để chia sẻ kiến thức bản thân học được trong quá trình “cơm áo gạo tiền” đây. Các bạn có thể theo dõi mình thêm qua một số nền tảng bên dưới nhé: Linkedin: https://www.linkedin.com/in/phuc-ngo-728433346 Viblo: https://viblo.asia/u/NHDPhucIT Patreon: https://www.patreon.com/felix_ngo
Nếu bài này hữu ích, đừng quên tặng mình một upvote, bookmark để ủng hộ các bạn nhé
Ởi bài trước, ta đã thực hành đánh INDEX theo chuẩn ESR Khi Filter và Sort cùng tồn tại trong truy vấn. Tức là ta đã làm việc với E và S trong bộ ba ESR. Hôm nay, ta sẽ thêm R vào để hoàn thiện nhé
1. Bài toán
Vẫn là bảng dữ liệu Orders với hơn 25 triệu documents mà ta đã tạo ở bài trước, vẫn là query cũ ở bài trước, nhưng ta sẽ thêm 1 điều kiện, đó là:
Giá trị của đơn hàng (
price
) phải lớn hơn 50
Rồi, giờ nhìn lại câu truy vấn mới của chúng ta nha:
[ { $match: { status: "completed", price: {$gt: 50} } }, { $sort: { quantity: 1 } },
]
Ta phân tích lại thành phần của nó nhé:
- E: (Equality):
status: "completed"
- S: (Sort):
quantity: 1
- R (Range):
price: {$gt: 50}
Okay, dễ hiểu phải không nào, thực nghiệm thôi. Ở phần thực nghiệm này, mình sẽ viết ngắn gọn nha. Vì các bước thực hiện ta đã làm quen ở bài trước rồi
2. Thực nghiệm với Single Index
2.1. Single Index trên trường status
Tạo Index trước nhé:
Và đây là kết quả:
Phân tích nha:
- Thời gian thực thi:
12s
- Số lượng documents trả về là 7_917_616
- Quá trình thực thi chia làm 3 giai đoạn
- IXSCAN: Scan theo Index
status
mà ta đã đánh dấu. Lúc này, có tổng cộng 8_333_739 documents thỏa mãn điều kiện, tiêu tốn chỉ1.8s
- FETCH: Ở bước này, MongoDB mới tiến hành lọc những documents thỏa điều kiện thứ 2 là
price > 50
, ta sẽ còn lại đúng 7_917_616 documents thỏa điều kiện, tiêu tốn3.8s
- Cuối cùng, quá trình SORT diễn ra vì ta không có INDEX trên đó, tiêu tốn
6.4s
- IXSCAN: Scan theo Index
2.2. Single Index trên trường price
Xóa Index cũ và tạo mới nhé:
Kết quả cho phương án này:
Phân tích nha:
- Thời gian thực thi:
53s
. Ôi nhiều quá - Số lượng documents trả về là 7_917_616
- Quá trình thực thi chia làm 3 giai đoạn
- IXSCAN: Scan theo Index
price
mà ta đã đánh dấu. Lúc này, có tổng cộng 23_756_377 documents thỏa mãn điều kiện (gấp 3 lần phương án tiền nhiệm), tiêu tốn đến5.1s
- FETCH: Ở bước này, MongoDB mới tiến hành lọc những documents thỏa điều kiện ban đầu là
status = "completed"
, ta sẽ còn lại đúng 7_917_616 documents thỏa điều kiện, tiêu tốn thời gian cực lớn là39.6s
- Cuối cùng, quá trình SORT diễn ra vì ta không có INDEX trên đó, tiêu tốn
7.3s
- IXSCAN: Scan theo Index
Như vậy, điểm khác biệt lớn nhất chính là ở trình IXSCAN và FETCH. Số lượng documents lớn hơn dẫn thời gian cần cho việc tìm kiếm, fetch và lọc dữ liệu tăng lên rất nhiều
2.3. Single Index trên trường quantity
Phương án này ta đã thực nghiệm và giải thích ở bài trước, nên mình sẽ không thực nghiệm ở đây nữa nhé
3. Compound Index
Vẫn như thường lệ, ta sẽ thử trên cả 2 phương án nha. Nhưng trước hết, cùng mình đánh INDEX thử Index chỉ dựa trên Filter, tức là chỉ E (status
) và S (price
) xem sao nha:
3.1. Đánh Index chỉ dựa trên Filter, tức là chỉ E (status
) và S (price
)
Tạo Index thôi:
Kết quả ta thu được là:
Vẫn là 3 giai đoạn như trước vì ta không chạm đến Index cho SORT. Tuy nhiên, ta thấy ngay từ bước IXSCAN, ta đã lọc được đúng 7_917_616 documents nhờ đánh INDEX cho cả 2 Filter, tiêu tốn 2.4s
thôi, quá trình còn lại là FECTH và SORT như thường lệ, lần lượt tiêu tốn thêm 12.3s
và 6.7s
3.2. Tuân thủ ESR
Theo đúng quy tắc, thì INDEX chúng ta cần tạo sẽ theo thứ tự là status
=> quantity
=> price
Kết quả mà ta mong đợi đây rồi:
Quá trình lúc này chỉ còn 2 giai đoạn, nhờ ta đã lược bớt được giai đoạn SORT
- IXSCAN; Tương tự phương án đánh Compound Index trên filter, ngay từ bước này, ta đã chọn được đúng 7_917_616 documents, tiêu tốn
3.1s
- FETCH: Nhờ đó, việc còn lại là lấy dữ liệu về thôi, thêm
12s
cho quá trình này nữa - Tổng thời gian thực thi là khoảng
12s
thôi nè
3.3. Không tuân thủ ESR
Giờ thử đảo ngược thứ tự 1 chút nhé: status
vần đi đầu, nhưng ta sẽ đưa price
lên trước, rồi mới đến quantity
. Cách đánh này rất nhiều bạn áp dựng vì thường đánh hết Filter, sau đó mới đánh đến SORT
Xem kết quả nhé:
Thời gian thực thi của chúng ta đã tăng lên thành 25s
, dù cho ở bước IXSCAN, ta đã lọc đúng 7_917_616 documents, tiêu tốn 2.4s
. Tuy nhiên, do ta đang đặt price
lên trước quantity
, nên MongoDB không thể tận dụng thứ tự SORT cho Index đó, dẫn đến ta phải có thêm bước SORT tieue tốn 7.3s
. Đây chính là nguyên do mà thời gian của chúng ta tăng lên
4. Kết luận
À thì có gì để kết luận nữa đâu, vẫn là ta nên tuân thủ quy tắc ESR khi đánh Index nhé. Ở phần tiếp theo, mình sẽ giới thiệu thêm một số query phức tạp hơn nha
Nếu bài này hữu ích, đừng quên tặng mình một upvote, bookmark để ủng hộ các bạn nhé. Nếu có thắc mắc gì hay ý kiến gì trao đổi, bạn có thể để lại comment nha.
Ngoài ra, các bạn có thể kết nối với mình qua: Linkedin: https://www.linkedin.com/in/phuc-ngo-728433346 Viblo: https://viblo.asia/u/NHDPhucIT Patreon: https://www.patreon.com/felix_ngo
.
Xin chào và hẹn gặp lại