CodeGym /Các khóa học /SQL SELF /Vấn đề của việc tạo quá nhiều index

Vấn đề của việc tạo quá nhiều index

SQL SELF
Mức độ , Bài học
Có sẵn

Index đúng là một cách cực kỳ xịn để database của bạn chạy nhanh hơn, nhưng như người ta nói, “cái gì nhiều quá cũng không tốt”. Không phải index nào cũng hữu ích, và nếu bạn tạo quá nhiều index thì đôi khi lại phản tác dụng. Nghe hơi ngược đời nhỉ, nhưng đúng là như vậy. Cùng tìm hiểu kỹ hơn nhé.

Hãy tưởng tượng một thư viện lớn, nơi bạn có nhiều danh mục để tìm sách — ví dụ, theo tác giả, theo thể loại, theo năm xuất bản. Mỗi danh mục như vậy giúp bạn tìm sách nhanh hơn. Nhưng nếu có quá nhiều danh mục — ví dụ, cho từng từ trong tên sách hoặc từng chi tiết nhỏ — thì thay vì giúp đỡ, nó lại gây rối: tìm kiếm lâu hơn, tốn nhiều chỗ để lưu danh mục, và thủ thư phải liên tục cập nhật tất cả các danh sách này.

Trong database, index cũng hoạt động kiểu như vậy: nó giúp bạn tìm dữ liệu nhanh, nhưng nếu có quá nhiều index, mỗi lần thêm hoặc sửa dữ liệu thì phải cập nhật hết các index đó, rất mệt. Ổ cứng cũng bị chiếm chỗ nhiều hơn. Thậm chí, khi có quá nhiều index, hệ thống có thể bị “rối não” không biết nên dùng cái nào.

Vậy nên, giống như danh mục trong thư viện, index cũng cần vừa đủ — có vài cái cần thiết và hiệu quả là ngon rồi, chứ không cần cả đống vô dụng.

Giờ thử đóng vai “thám tử PostgreSQL” nhé. Giả sử bạn thêm ba index cho một cột. Bạn nghĩ làm vậy sẽ tăng hiệu năng. Nhưng thử tưởng tượng xem:

  • Nếu bảng của bạn là một danh sách lớn các sinh viên, mà lại có ba index, thì mỗi lần thêm sinh viên mới sẽ phải cập nhật cả ba index. Nghe chẳng giống “tăng tốc” gì cả, đúng không?
  • Mà nếu bạn có 10 bảng kiểu vậy, mỗi bảng lại bị “ngập” index? Hiệu năng của cả database sẽ tụt dốc không phanh.

Làm sao biết bạn có bị thừa index không?

Việc đầu tiên để kiểm tra là xem các index hiện có. Trong PostgreSQL, bạn có thể dùng lệnh:

\d ten_bang

Lệnh này sẽ cho bạn thấy bảng, các cột và các index liên quan. Nếu bạn thấy một đống index gắn với một bảng, thì nên suy nghĩ lại rồi đó.

Một công cụ hữu ích nữa là view hệ thống pg_stat_user_indexes. Nó cho bạn biết index nào được dùng nhiều, index nào là “hàng tồn kho”:

SELECT
    relname AS table_name,
    indexrelname AS index_name,
    idx_scan AS index_scans
FROM
    pg_stat_user_indexes
WHERE
    idx_scan = 0;

Nếu idx_scan bằng 0, nghĩa là index đó chưa từng được dùng trong query nào. Index kiểu này là ứng viên sáng giá để xóa đi.

Ví dụ về việc tạo quá nhiều index

Giả sử bạn có một bảng users như sau:

CREATE TABLE users (
    user_id SERIAL PRIMARY KEY,
    email VARCHAR(255) UNIQUE,
    username VARCHAR(50),
    created_at TIMESTAMP DEFAULT NOW()
);

Và bạn có ba index:

-- Index cho email
CREATE INDEX idx_users_email ON users (email);

-- Index cho username
CREATE INDEX idx_users_username ON users (username);

-- Index cho created_at
CREATE INDEX idx_users_created_at ON users (created_at);

Giờ xem các query thường dùng nhé:

  1. Tìm user theo email.
  2. Tìm user theo username.
  3. Sắp xếp user theo created_at.

Nghe có vẻ các index này hữu ích. Nhưng vấn đề là: nếu các query này rất hiếm khi chạy (kiểu mỗi tuần một lần), thì tạo index là không cần thiết. Thậm chí, nếu có index mà chẳng bao giờ dùng, nó chỉ làm nặng thêm khi insert/update dữ liệu thôi.

Ví dụ: giả sử bảng users có dữ liệu như sau:

user_id email username created_at
1 alex.lin@mail.com alexlin 2024-06-15 10:23:00
2 anna.min@mail.com annamin 2024-06-16 12:47:00
3 otto.song@mail.com ottosong 2024-06-17 08:30:00
4 maria.chi@mail.com mariachi 2024-06-18 14:10:00

Nếu gần như không bao giờ query theo username, thì index idx_users_username sẽ không được dùng (idx_scan = 0) và có thể xóa đi cho nhẹ database.

Nói chung, index là công cụ cực kỳ hữu ích, nhưng phải dùng hợp lý. Có vài cái cần thiết và dùng thường xuyên thì tốt hơn là cả đống mà chẳng ai động tới.

Làm sao tránh bị thừa index?

  1. Phân tích các index đang dùng. Như đã nói ở trên, hãy kiểm tra thống kê sử dụng index bằng pg_stat_user_indexes. Nếu index nào gần như không dùng, có thể xóa luôn:
DROP INDEX IF EXISTS ten_index;
  1. Chỉ tạo index cho các query thường dùng. Trước khi thêm index, tự hỏi bản thân mấy câu này:
  • Cột này có thường xuất hiện trong WHERE, ORDER BY, GROUP BY không?
  • Bảng có nhiều dữ liệu không?
  • Query thực sự chạy quá chậm nếu không có index không?

Nếu trả lời “không” cho bất kỳ câu nào, thì có lẽ không cần tạo index đâu.

  1. Dùng index tổng hợp (composite index). Nếu bạn hay query nhiều cột cùng lúc, thay vì tạo từng index riêng lẻ, hãy tạo một index tổng hợp:
CREATE INDEX idx_users_email_username ON users (email, username);

Cách này sẽ tăng tốc cho các query lọc theo cả email username cùng lúc.

  1. Thường xuyên rà soát lại các index. Khi database phát triển, các query của bạn có thể thay đổi. Cái gì hữu ích năm ngoái, giờ có thể thành thừa. Thỉnh thoảng nên kiểm tra lại và xóa những index không còn dùng nữa.

Tối ưu index qua ví dụ

Quay lại bảng users của chúng ta. Thay vì ba index riêng biệt, bạn có thể tối ưu như sau:

  • Bỏ index riêng cho created_at nếu hiếm khi sắp xếp theo cột này.
  • Thay vì hai index riêng cho emailusername, tạo một index tổng hợp:
CREATE INDEX idx_users_email_username ON users (email, username);

Tóm lại: Bí quyết cân bằng là gì?

Giống như nhiều thứ trong lập trình, nguyên tắc tối giản luôn đúng: “Càng ít càng tốt”. Đừng index mọi cột chỉ vì bạn có thể. Hãy nghĩ xem bạn cần index để làm gì và nó có thực sự giúp query nhanh hơn không. Hãy thực tế và nhớ rằng lập trình viên giỏi không phải là người tạo index bừa bãi, mà là người hiểu rõ tác động của index và dùng chúng hiệu quả.

Giờ thì bạn đã có “vũ khí” trong tay để tránh thảm họa thừa index và làm database của mình nhanh như báo, chứ không phải chậm như rùa vác cả đống index vô dụng.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION