SQL Index Under the Hood (Part 1)
hoanggg2110
Tác giả

SQL Index Under the Hood (Part 1): Vì sao Database ngày càng chậm khi dữ liệu lớn?
"Muốn hiểu Index, trước tiên hãy hiểu Database đang làm gì khi chưa có Index."
Sau bài viết này, bạn sẽ hiểu
Vì sao query chạy nhanh lúc đầu nhưng chậm dần theo thời gian
Database tìm dữ liệu bằng cách nào
Full Table Scan là gì
Vì sao luôn cần tạo Index
Một đêm production
2 giờ sáng, Nam (Backend Dev) bị dựng dậy vì khách hàng phàn nàn. CPU 25%, RAM 43%, disk còn trống, log sạch — nhưng lệnh sau mất tới 8 giây:
SELECT * FROM orders WHERE customer_email = 'john@gmail.com';
Không JOIN, không GROUP BY, không subquery. Vậy Database đã làm gì suốt 8 giây đó?

Ví dụ: bạn là thủ thư
Thư viện 10 triệu cuốn sách, có người hỏi tìm Clean Code.
Cách 1: lật từng cuốn — chắc chắn tìm ra nhưng rất lâu.
Cách 2: tra mục lục → Kệ A12 → Hàng 3 → Cuốn 18 — chưa đến 10 giây.
Khác biệt không nằm ở tốc độ đọc, mà ở việc có bản đồ hay không.

Database đọc theo Page, không theo Row
Nhiều người hình dung Database đọc từng dòng một. Thực tế, đơn vị đọc dữ liệu là Page — một "chiếc hộp" chứa nhiều dòng (PostgreSQL: ~8KB/page).
➡️ Chỉ cần 1 dòng trong Page, Database vẫn phải đọc cả Page.

Khi chưa có Index: Full Table Scan
Với bảng orders 10 triệu dòng, Database không biết email cần tìm nằm ở đâu → phải đọc lần lượt từng Page cho đến khi tìm thấy. Quá trình này gọi là Full Table Scan (PostgreSQL gọi là Seq Scan) — không phải lỗi, mà là cách duy nhất khi không có thông tin bổ trợ.
Vì sao dữ liệu càng lớn càng chậm? Thư viện 100 cuốn thì tìm tay cũng nhanh; 10 triệu cuốn thì khác hẳn. Query chậm không phải vì SQL đổi hay server yếu, mà vì lượng dữ liệu cần đọc tăng lên.
Hands-on Lab
CREATE TABLE customers (
id BIGSERIAL PRIMARY KEY,
name TEXT,
email TEXT,
created_at TIMESTAMP
);
INSERT INTO customers(name, email, created_at)
SELECT 'Customer ' || i, 'customer_' || i || '@gmail.com', NOW()
FROM generate_series(1,1000000) i;
EXPLAIN ANALYZE
SELECT * FROM customers WHERE email='customer_999999@gmail.com';
Kết quả sẽ hiện Seq Scan on customers — PostgreSQL đang quét tuần tự toàn bộ bảng để tìm một dòng duy nhất. (Part 4 sẽ benchmark với 100K, 1M, 10M bản ghi.)

Hiểu lầm phổ biến
"Query chậm vì CPU yếu."
Thực tế, nút thắt lớn nhất thường là phải đọc quá nhiều dữ liệu từ ổ đĩa — không phải CPU. Mục tiêu tối ưu không phải "chạy nhanh hơn" mà là đọc ít dữ liệu hơn.

Production tip: thay vì hỏi "có nên tạo Index không?", hãy hỏi "Database đang phải đọc bao nhiêu dữ liệu để trả lời query này?"
Tổng kết
✅ Database không đọc từng dòng, mà đọc theo Page
✅ Không có Index → Full Table Scan, đọc toàn bộ dữ liệu
✅ Dữ liệu càng lớn, chi phí đọc càng cao → query càng chậm
Phần tiếp theo
Nếu Full Table Scan giống như lật từng cuốn sách, thì Index thực chất là gì và vì sao nó giúp Database tìm ra 1 dòng giữa hàng chục triệu dòng chỉ sau vài lần đọc? Hẹn gặp ở Part 2 🚀
Thích bài viết này?
Nội dung trên Vết Mực luôn được chia sẻ miễn phí. Nếu bài viết mang lại giá trị cho bạn, hãy cân nhắc ủng hộ để chúng mình có thể duy trì máy chủ, phát triển thêm tính năng mới và tiếp tục xây dựng một không gian dành cho những người yêu viết lách. ✨
Các cách ủng hộ:
- •Viết và đăng bài trên Vết Mực
- •Chia sẻ bài viết với bạn bè
- •Góp ý để chúng mình cải thiện sản phẩm qua email: nsikhoa@gmail.com
Dù bạn chọn ủng hộ hay chỉ đơn giản là tiếp tục đọc và chia sẻ bài viết, đó đều là nguồn động lực rất lớn với chúng mình. ❤️
Bình luận
Đăng nhập để để lại bình luận.