CodeGym /Các khóa học /SQL SELF /Những vấn đề thường gặp khi làm việc với index

Những vấn đề thường gặp khi làm việc với index

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

Ngay cả cái máy xịn nhất cũng sẽ tịt nếu đổ nước chanh vào thay vì xăng. Index trong PostgreSQL cũng vậy. Nó là công cụ cực mạnh, nhưng phải biết dùng cho đúng. Cùng xem qua vài vấn đề điển hình liên quan đến index nhé.

Vấn đề 1: tạo quá nhiều index

Đầu tiên, nhớ lại chủ đề của bài giảng trước-đó-nữa. Khi bạn tạo quá nhiều index trên một bảng, PostgreSQL phải xử lý từng cái để giữ cho chúng luôn cập nhật. Điều này ảnh hưởng trực tiếp đến các thao tác ghi, cập nhật và xóa. Vì mỗi index không chỉ phải cập nhật mà còn phải đồng bộ nữa!

Giả sử tụi mình có bảng students:

CREATE TABLE students (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(255) UNIQUE,
    age INTEGER,
    grade INTEGER
);

Và bạn quyết định tạo index cho từng cột “cho chắc ăn”:

CREATE INDEX idx_students_name ON students(name);
CREATE INDEX idx_students_age ON students(age);
CREATE INDEX idx_students_grade ON students(grade);

Bây giờ tưởng tượng bạn chèn 10 ngàn bản ghi mới. PostgreSQL không chỉ ghi dữ liệu vào bảng mà còn phải cập nhật cả ba index này. Nếu dữ liệu nhiều, tốc độ ghi sẽ giảm và hiệu năng hệ thống cũng tụt theo.

Làm sao tránh lỗi này? Trước khi tạo index, tự hỏi hai câu sau:

  1. Cột này có thường xuyên dùng để lọc (WHERE), sắp xếp (ORDER BY) hoặc group (GROUP BY) không?
  2. Truy vấn có dùng index này không hay vẫn sẽ quét toàn bộ bảng?

Nếu câu trả lời cho cả hai là “hiếm” hoặc “không bao giờ”, thì khỏi cần index luôn.

Vấn đề 2: chọn sai cột để tạo index

Tạo index trên dữ liệu ít giá trị khác biệt cũng như rót trà vào ly đã bị dán kín: gần như vô dụng. Nếu cột chỉ có 2-3 giá trị duy nhất, PostgreSQL thường sẽ quét hết bảng thay vì dùng index.

Giả sử tụi mình có bảng courses:

CREATE TABLE courses (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255),
    level VARCHAR(10) -- Có thể chỉ là 'Beginner', 'Intermediate' hoặc 'Advanced'
);

Và bạn tạo index trên cột level:

CREATE INDEX idx_courses_level ON courses(level);

Nhưng truy vấn này:

SELECT * FROM courses WHERE level = 'Beginner';

có thể không dùng index, vì PostgreSQL sẽ tính ra rằng quét hết bảng còn nhanh hơn là tra index. Điều này càng đúng với bảng nhỏ và dữ liệu ít giá trị khác biệt.

Vậy nên index chỉ hợp lý trên cột có độ phân biệt cao (tức là nhiều giá trị khác nhau). Với dữ liệu ít giá trị, nên dùng cách tối ưu khác, ví dụ như partition bảng.

Vấn đề 3: index cũ không còn dùng nữa

Đôi khi index được tạo ra rồi bị quên lãng, dù chẳng ai dùng nữa. Giống như file trên desktop: ban đầu chỉ có hai, ba, năm cái. Rồi tự nhiên bạn nhận ra mình tốn cả đống thời gian đảo mắt tìm icon cần thiết... Quen không?

Ví dụ, tụi mình tạo index cho chức năng cũ, sau đó đổi logic truy vấn và thêm index mới. Index cũ không ai dùng nữa nhưng vẫn chiếm chỗ và làm chậm thao tác ghi.

Để tránh chuyện này, hãy thường xuyên kiểm tra và phân tích index. PostgreSQL có sẵn chỉ số tiện lợi:

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

Ở đây idx_scan cho biết có bao nhiêu truy vấn đã dùng index đó. Nếu giá trị là 0, nghĩa là index không dùng tới và có thể xóa đi:

DROP INDEX idx_courses_level;

Vấn đề 4: index trên cột thường xuyên cập nhật

Nếu bạn tạo index trên cột mà bạn hay cập nhật, PostgreSQL phải rebuild lại index mỗi lần thay đổi. Điều này có thể làm hiệu năng giảm đáng kể.

Hãy tưởng tượng bảng lưu thông tin đơn hàng:

CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    status VARCHAR(20), -- Có thể thay đổi nhiều lần (ví dụ "mới", "đang xử lý", "hoàn thành")
    total NUMERIC(10, 2)
);

Bạn tạo index trên cột status để lọc theo trạng thái nhanh hơn:

CREATE INDEX idx_orders_status ON orders(status);

Nhưng nếu status thay đổi hàng chục lần cho mỗi bản ghi, index sẽ làm hiệu năng tệ đi.

Để tránh tình huống này, đừng tạo index trên cột thay đổi thường xuyên. Nếu vẫn cần index, hãy cân nhắc dùng partial index:

CREATE INDEX idx_orders_status_partial
ON orders(status) 
WHERE status = 'đang xử lý';

Như vậy, index chỉ cập nhật cho bản ghi có giá trị đó thôi.

Vấn đề 5: Ràng buộc UNIQUE trên cột không cần thiết

Index unique (UNIQUE) tự động được tạo để đảm bảo dữ liệu không trùng. Nhưng nếu không thực sự cần thiết, các index này chỉ làm nặng hệ thống.

Ví dụ, tụi mình tạo bảng log:

CREATE TABLE logs (
    id SERIAL PRIMARY KEY,
    message TEXT,
    created_at TIMESTAMP UNIQUE
);

Nếu mỗi giây có hàng ngàn bản ghi mới, việc đảm bảo unique trên created_at sẽ tạo gánh nặng lớn.

Để mọi thứ ổn, chỉ nên để ràng buộc UNIQUE ở nơi thực sự cần. Trong ví dụ này, nếu không cần unique trên created_at, hãy thay bằng index thường:

CREATE INDEX idx_logs_created_at ON logs(created_at);

Vấn đề 6: dùng sai index kết hợp nhiều cột

Index kết hợp (multi-column indexes) rất hữu ích nếu truy vấn lọc hoặc sắp xếp theo nhiều cột cùng lúc. Nhưng phải tạo đúng thứ tự, không thì index sẽ bị bỏ xó.

Ví dụ, tụi mình có index này:

CREATE INDEX idx_students_name_grade ON students(name, grade);

Index này sẽ được dùng nếu truy vấn lọc hoặc sắp xếp theo cả hai cột:

SELECT * FROM students WHERE name = 'Alice' AND grade = 90;

Nhưng truy vấn này:

SELECT * FROM students WHERE grade = 90;

không dùng index này, vì trường name đứng trước.

Để tránh lỗi này, chỉ tạo index kết hợp theo đúng thứ tự mà truy vấn thường dùng nhất. Nếu cần lọc theo từng cột riêng, hãy tạo index riêng cho từng cột.

Mẹo hữu ích

Theo dõi việc sử dụng index. PostgreSQL có view hệ thống pg_stat_user_indexes để xem index nào đang được dùng, index nào không.

Tối ưu truy vấn cùng với index. Truy vấn dở thì có index cũng vẫn dở thôi.

Đừng quên xóa index thừa. Index cũ chỉ chiếm chỗ và làm chậm thao tác ghi.

Vậy là xong rồi nha mọi người! Index là công cụ cực mạnh, nhưng nhớ rằng sức mạnh lớn đi kèm trách nhiệm lớn. Dùng index cho hợp lý, database của bạn sẽ chạy như tên lửa SpaceX luôn!

1
Khảo sát/đố vui
, cấp độ , bài học
Không có sẵn
Vấn đề khi tạo quá nhiều index
Vấn đề khi tạo quá nhiều index
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION