[SQL] Indexes

Chúng ta lại gặp nhau để tiếp tục khám phá thế giới SQL. Lần này, tôi sẽ giới thiệu cho bạn một khái niệm cực kỳ quan trọng để tăng tốc độ truy vấn dữ liệu: Indexes (Chỉ mục). Với vai trò người hướng dẫn, tôi sẽ giải thích cặn kẽ, kèm ví dụ gần gũi để bạn dễ dàng hình dung và áp dụng nhé.
Hãy tưởng tượng bạn có một cuốn sách giáo trình rất dày. Khi muốn tìm một chủ đề cụ thể, ví dụ như "Subquery", bạn sẽ làm gì? Lật từng trang từ đầu đến cuối ư? Chắc chắn là không rồi! Bạn sẽ mở phần mục lục (index) ở cuối sách, tìm đến chữ "S", tìm "Subquery", và xem nó nằm ở trang nào. Sau đó, bạn chỉ cần lật thẳng đến trang đó. Nhanh hơn rất nhiều đúng không?
SQL Index cũng hoạt động tương tự như vậy!
1. Indexes (Chỉ mục) là gì?
Định nghĩa: Index trong cơ sở dữ liệu là một cấu trúc dữ liệu đặc biệt, được tạo ra trên một hoặc nhiều cột của một bảng. Nó chứa các giá trị từ (các) cột được đánh index và con trỏ (pointer) chỉ đến vị trí thực tế của hàng dữ liệu tương ứng trong bảng.
Mục đích chính: Giúp hệ quản trị cơ sở dữ liệu (CSDL) tìm kiếm dữ liệu nhanh hơn đáng kể, đặc biệt là với các bảng lớn. Thay vì phải "đọc" toàn bộ bảng (Full Table Scan) để tìm các hàng thỏa mãn điều kiện, CSDL có thể sử dụng Index để "nhảy" thẳng đến vị trí cần tìm.
Cấu trúc phổ biến: Thường là dạng cây (như B-Tree), cho phép tìm kiếm, sắp xếp, thêm, xóa dữ liệu một cách hiệu quả. Bạn không cần hiểu sâu về B-Tree ngay, chỉ cần biết nó là cấu trúc giúp tìm kiếm nhanh.
2. Indexes và Query Optimization (Tối ưu hóa truy vấn)
Đây chính là lợi ích lớn nhất của Index.
a. Tại sao Index tăng tốc truy vấn?
Hãy quay lại ví dụ bảng NhanVien
của chúng ta:
MaNV | TenNV | Luong | MaPB |
NV01 | Nguyễn Văn A | 60000 | PB01 |
... | ... | ... | ... |
NV99 | Trần Văn Z | 70000 | PB02 |
Export to Sheets
Giả sử bảng này có 1 triệu nhân viên. Bây giờ, bạn muốn tìm thông tin của nhân viên có MaNV = 'NV789123'
:
SQL
SELECT MaNV, TenNV, Luong, MaPB
FROM NhanVien
WHERE MaNV = 'NV789123';
KHÔNG có Index trên cột
MaNV
:CSDL phải làm gì? Nó giống như bạn lật từng trang sách vậy. CSDL sẽ phải đọc tuần tự từng hàng trong bảng
NhanVien
, từ hàng đầu tiên đến hàng cuối cùng.Với mỗi hàng, nó so sánh giá trị cột
MaNV
với 'NV789123'.Nếu tìm thấy, nó trả về hàng đó. Nếu không (hoặc cần tìm tất cả các kết quả khớp), nó phải đọc hết 1 triệu hàng! -> Rất chậm! Đây gọi là Full Table Scan.
CÓ Index trên cột
MaNV
:Bây giờ, CSDL có một "cuốn sổ mục lục" riêng cho
MaNV
. Cuốn sổ này đã được sắp xếp (ví dụ theo thứ tự A-Z của MaNV).CSDL sẽ tìm kiếm 'NV789123' trong Index này (rất nhanh, giống như tìm trong mục lục sách).
Khi tìm thấy 'NV789123' trong Index, nó sẽ lấy được "số trang" (con trỏ) chỉ đến vị trí chính xác của hàng dữ liệu 'NV789123' trong bảng
NhanVien
gốc.CSDL "nhảy" thẳng đến vị trí đó và lấy dữ liệu. -> Nhanh hơn rất nhiều!
b. Các loại truy vấn được hưởng lợi từ Index:
Mệnh đề
WHERE
: Đây là trường hợp phổ biến nhất. Index trên các cột dùng trongWHERE
giúp lọc dữ liệu nhanh chóng.Phép nối
JOIN
: Index trên các cột dùng để nối bảng (thường là khóa ngoại -MaPB
trong ví dụ của chúng ta) giúp CSDL tìm các hàng khớp giữa các bảng hiệu quả hơn nhiều.Mệnh đề
ORDER BY
: Nếu bạn tạo Index trên cột dùng để sắp xếp, CSDL có thể lấy dữ liệu theo thứ tự trực tiếp từ Index mà không cần thực hiện thêm bước sắp xếp tốn kém.Mệnh đề
GROUP BY
: Tương tựORDER BY
, Index có thể giúp tăng tốc việc nhóm dữ liệu.Tìm
MIN()
/MAX()
: Nếu cột có Index, việc tìm giá trị nhỏ nhất/lớn nhất có thể rất nhanh vì Index thường đã được sắp xếp.
c. Mặt trái của Index - Chi phí phải trả:
Index không phải là "viên đạn bạc" chỉ có lợi mà không có hại.
Tốn dung lượng lưu trữ: Index là một cấu trúc dữ liệu riêng, nó chiếm thêm dung lượng trên đĩa cứng. Càng nhiều Index, càng tốn dung lượng.
Làm chậm các thao tác
INSERT
,UPDATE
,DELETE
:Khi bạn thêm một hàng mới (
INSERT
), CSDL không chỉ ghi dữ liệu vào bảng mà còn phải cập nhật tất cả các Index liên quan đến bảng đó.Khi bạn xóa một hàng (
DELETE
), các mục tương ứng trong Index cũng phải bị xóa.Khi bạn cập nhật giá trị của một cột đã được đánh Index (
UPDATE
), Index đó cũng phải được cập nhật.Càng nhiều Index trên một bảng, các thao tác chỉnh sửa dữ liệu (ghi) càng trở nên chậm hơn.
Do đó, việc sử dụng Index là một sự đánh đổi: Tăng tốc độ đọc (SELECT
) nhưng làm giảm tốc độ ghi (INSERT
, UPDATE
, DELETE
) và tốn thêm dung lượng. Mục tiêu là tìm sự cân bằng phù hợp.
3. Managing Indexes (Quản lý chỉ mục)
Việc tạo và quản lý Index là một phần quan trọng của việc thiết kế và bảo trì CSDL.
a. Khi nào nên tạo Index?
Cột thường xuyên được sử dụng trong mệnh đề
WHERE
để lọc dữ liệu.Cột thường xuyên được sử dụng trong điều kiện
JOIN
(thường là khóa chính và khóa ngoại).Cột thường xuyên được sử dụng trong mệnh đề
ORDER BY
hoặcGROUP BY
.Cột có tính chọn lọc cao (High Selectivity): Nghĩa là cột đó có nhiều giá trị duy nhất hoặc gần như duy nhất so với tổng số hàng. Ví dụ:
MaNV
(mỗi nhân viên có mã riêng) là ứng viên tốt cho Index. Ngược lại, cộtGioiTinh
(chỉ có 2-3 giá trị Nam/Nữ/Khác) thường có tính chọn lọc thấp, đánh Index trên cột này ít mang lại lợi ích, thậm chí có thể làm chậm hơn.Bảng có số lượng hàng lớn (vài ngàn hàng trở lên). Với bảng nhỏ, Full Table Scan có thể đã đủ nhanh.
b. Cách tạo Index (Cú pháp cơ bản)
SQL
CREATE INDEX ten_index
ON ten_bang (ten_cot1, ten_cot2, ...);
ten_index
: Tên bạn đặt cho Index (nên đặt theo quy tắc để dễ quản lý, ví dụ:idx_TenBang_TenCot
).ten_bang
: Tên bảng bạn muốn tạo Index.(ten_cot1, ten_cot2, ...)
: Danh sách các cột bạn muốn đưa vào Index.
Ví dụ:
Tạo Index trên cột
MaPB
của bảngNhanVien
(thường là khóa ngoại):SQL
CREATE INDEX idx_NhanVien_MaPB ON NhanVien (MaPB);
-> Giúp tăng tốc các truy vấn lọc theo
MaPB
hoặcJOIN
bảngNhanVien
vớiPhongBan
quaMaPB
.Tạo Index trên cột
Luong
:SQL
CREATE INDEX idx_NhanVien_Luong ON NhanVien (Luong);
-> Giúp tăng tốc truy vấn lọc theo khoảng lương (
WHERE Luong > 50000
) hoặc sắp xếp theo lương (ORDER BY Luong
).Tạo Index ghép (Composite Index) trên nhiều cột:
SQL
CREATE INDEX idx_NhanVien_PhongBan_Luong ON NhanVien (MaPB, Luong);
-> Index này rất hữu ích cho các truy vấn lọc đồng thời trên cả
MaPB
vàLuong
(ví dụ:WHERE MaPB = 'PB01' AND Luong > 70000
). -> Thứ tự cột trong Index ghép rất quan trọng. Index(MaPB, Luong)
cũng có thể giúp tăng tốc truy vấn chỉ lọc theoMaPB
, nhưng thường không hiệu quả (hoặc không dùng được) cho truy vấn chỉ lọc theoLuong
.Tạo Index duy nhất (Unique Index): Đảm bảo tất cả giá trị trong cột (hoặc tổ hợp cột) là duy nhất, đồng thời cũng giúp tăng tốc truy vấn. Khóa chính (Primary Key) thường tự động có một Unique Index đi kèm.
SQL
CREATE UNIQUE INDEX idx_NhanVien_MaNV_Unique ON NhanVien (MaNV);
(Nếu
MaNV
đã là Primary Key, bước này có thể không cần thiết vì CSDL đã tự tạo).
c. Khi nào nên xóa Index?
Index không còn được sử dụng (không có truy vấn nào dùng đến nó nữa).
Index không hiệu quả (ví dụ: Index trên cột có tính chọn lọc quá thấp).
Index làm chậm các thao tác ghi (
INSERT
,UPDATE
,DELETE
) quá nhiều mà lợi ích tăng tốcSELECT
không đáng kể.Thay đổi cấu trúc bảng hoặc chiến lược tối ưu.
d. Cách xóa Index (Cú pháp cơ bản)
SQL
DROP INDEX ten_index
ON ten_bang; -- (Một số hệ CSDL không cần ON ten_bang)
-- Hoặc cú pháp khác tùy hệ CSDL, ví dụ:
-- DROP INDEX ten_index; (Nếu tên index là duy nhất trong DB)
Ví dụ:
SQL
DROP INDEX idx_NhanVien_Luong
ON NhanVien;
e. Các lưu ý khác khi quản lý Index:
Đừng đánh Index một cách mù quáng: Không phải cứ tạo Index cho mọi cột là tốt. Hãy phân tích các truy vấn thường dùng nhất và chỉ tạo Index cho những cột thực sự cần thiết.
Theo dõi và đánh giá: Sử dụng các công cụ của hệ quản trị CSDL (ví dụ:
EXPLAIN PLAN
,Query Analyzer
) để xem các truy vấn có đang sử dụng Index bạn tạo không và hiệu quả ra sao.Bảo trì Index: Theo thời gian và qua nhiều lần cập nhật dữ liệu, Index có thể bị "phân mảnh" (fragmentation), làm giảm hiệu quả. Các hệ CSDL thường có công cụ để
REBUILD
hoặcREORGANIZE
Index. (Đây là kiến thức nâng cao hơn).Cân nhắc Index bao hàm (Covering Index): Là Index chứa tất cả các cột mà một truy vấn cần. Khi đó, CSDL có thể trả lời truy vấn chỉ bằng cách đọc Index mà không cần truy cập vào bảng chính, rất nhanh chóng. Ví dụ: nếu có truy vấn
SELECT MaPB, Luong FROM NhanVien WHERE MaPB = 'PB01'
, thì Indexidx_NhanVien_PhongBan_Luong
ở trên chính là một Covering Index cho truy vấn này.
Subscribe to my newsletter
Read articles from Ha Ngoc Hieu directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
