Chào các bạn!
Trong việc quản lý dữ liệu, chúng ta thường xuyên phải đếm số lượng bản ghi trong các bảng. Một trong những hàm hữu ích nhất trong SQL chính là COUNT
, nhưng ít ai thực sự hiểu rõ sự khác biệt giữa các tham số khác nhau mà hàm này có thể nhận, chẳng hạn như COUNT(*)
, COUNT(1)
và COUNT(column)
.
Nội dung bài viết
Bài viết này sẽ giúp bạn hiểu rõ hơn về hiệu suất của từng loại câu lệnh đếm. Chúng ta sẽ khám phá:
- Câu lệnh đếm nào có hiệu suất tốt nhất
- Các yếu tố ảnh hưởng đến hiệu suất khi sử dụng hàm
COUNT
- Cách tối ưu cho việc đếm bản ghi trong các bảng lớn
1. Hiệu suất của các câu lệnh COUNT
Trước tiên, chúng ta hãy đi đến kết luận chung về hiệu suất của các loại câu lệnh đếm:
COUNT(*) = COUNT(1) > COUNT(primary key column) > COUNT(column)
1.1. COUNT() là gì?
Hàm COUNT(arg)
là một hàm tổng hợp dùng để đếm số lượng bản ghi thỏa mãn điều kiện nhất định. Tham số arg
có thể là một cột, hằng số hoặc đơn giản là ký tự *
. Câu lệnh COUNT(column)
sẽ đếm số lượng bản ghi có giá trị không phải NULL
trong cột đó.
Ví dụ:
SELECT COUNT(name) FROM member;
Lệnh này sẽ đếm số lượng bản ghi trong bảng member
mà trường name
không phải là NULL
.
1.2. So sánh COUNT(primary key column) và COUNT(1)
Khi đếm số lượng bản ghi thông qua COUNT(arg)
, MySQL sẽ tạo ra một biến count
và duyệt qua tất cả các bản ghi. Nếu giá trị của arg
khác NULL
, biến count
sẽ được tăng lên. Đặc biệt, khi sử dụng COUNT(1)
, MySQL sẽ không cần phải đọc giá trị của trường, do đó điều này giúp tiết kiệm thời gian tính toán:
SELECT COUNT(1) FROM member;
Khi chỉ có clustered index mà không có secondary index, InnoDB sẽ duyệt qua clustered index mà không cần đọc giá trị khóa chính, từ đó tăng tốc độ thực thi.
1.3. COUNT(*) hoạt động như thế nào?
Nhiều người nhầm lẫn rằng COUNT(*)
sẽ đọc tất cả các giá trị của trường trong bảng. Trên thực tế, MySQL chuyển đổi COUNT(*)
thành COUNT(0)
khi thực thi. Vì vậy, tốc độ thực thi của cả COUNT(*)
và COUNT(1)
là như nhau, không có sự khác biệt về hiệu suất.
1.4. Hiệu suất của COUNT(column)
Ví dụ:
SELECT COUNT(name) FROM member;
Với câu lệnh này, MySQL cần duyệt toàn bộ bảng để đếm, cho nên hiệu suất sẽ kém hơn so với COUNT(1)
và COUNT(*)
. Tuy nhiên, nếu trường column
có secondary index, hiệu suất có thể được cải thiện đáng kể.
2. COUNT trong các tình huống khác
2.1. Các Storage Engine khác nhau
Mỗi storage engine có cơ chế hoạt động riêng và điều này cũng ảnh hưởng đến cách thức hàm COUNT
được thực thi. Ví dụ, trong MyISAM, có metadata chứa giá trị row_count
, cho phép đếm nhanh chóng mà không cần phải scan toàn bộ bảng. Đối với InnoDB, mọi thứ thường phức tạp hơn.
2.2. COUNT khi có transaction
Với InnoDB, trong các tình huống có nhiều transaction, giá trị COUNT
có thể khác nhau tùy thuộc vào mức độ cách ly của transaction. Điều này có thể dẫn đến sự không nhất quán trong kết quả đếm khi cùng một lúc hai session thực hiện truy vấn.
3. Tối ưu hóa COUNT(*) cho bảng lớn
Khi làm việc với các bảng lớn có hàng triệu bản ghi, thời gian thực thi cho COUNT(*)
có thể rất lâu. Dưới đây là một số phương pháp tối ưu:
3.1. Ước lượng giá trị
Nếu không cần độ chính xác tuyệt đối, bạn có thể sử dụng lệnh EXPLAIN
để ước lượng số lượng bản ghi mà không cần quét bảng thực tế.
3.2. Tạo bảng đếm riêng
Một cách khác là tạo một bảng riêng để lưu trữ giá trị đếm. Khi thêm hoặc xóa bản ghi trong bảng chính, bạn có thể cập nhật giá trị trong bảng đếm.
Kết luận
Như vậy, để đạt hiệu suất tốt nhất khi đếm bản ghi trong MySQL, bạn nên:
- Sử dụng
COUNT(*)
hoặcCOUNT(1)
cho hiệu năng tốt nhất. - Tránh sử dụng
COUNT(column)
với các trường không có index vì hiệu suất kém. - Tận dụng secondary index nếu có thể để cải thiện tốc độ truy vấn.
Hy vọng bài viết này giúp ích cho bạn trong việc hiểu rõ hơn về hàm COUNT
và cách tối ưu hóa việc đếm trong MySQL. Hẹn gặp lại trong những bài viết tiếp theo!
Nếu bạn thấy bài viết hữu ích, hãy cho mình một lượt upvote 🔼 và chia sẻ nhé!
Cảm ơn các bạn rất nhiều!
🧑💻 70+ Ronin Engineers: https://ronin-engineer.github.io/c1/
📚️ System Design VN: https://fb.com/groups/systemdesign.vn
source: viblo