Học bằng cách đọc theo thứ tự

Index-Only Scan — Chỉ mục bỏ qua bảng

Đưa mọi cột truy vấn chạm vào chỉ mục và chuyến quay về bảng nền biến mất. Đây là Index-Only Scan (còn gọi là covering index). Bạn sẽ học các điều kiện làm nó hoạt động, cách nó hỏng ngay khi thiếu một cột, và cách gấp các cột bộ lọc WHERE vào một chỉ mục duy nhất, tất cả xác minh với EXPLAIN QUERY PLAN.

Bỏ qua tra cứu bảng — Index-Only Scan

Tra cứu chỉ mục thông thường tìm dòng đích trong chỉ mục, rồi quay về bảng nền để đọc các cột khác từng dòng một.

Chuyến quay về này gọi là table lookup (bước lấy một dòng từ bảng nền qua chỉ mục).

Khi tập kết quả lớn, các chuyến đi vòng đó dồn lại và bắt đầu tốn thời gian thực.

Nếu bạn dùng chỉ mục chứa mọi cột truy vấn tham chiếu, mọi giá trị đều ở ngay trong chỉ mục, và không cần quay về bản thân bảng.

Mẫu này, nơi chỉ mục một mình đưa ra kết quả, gọi là Index-Only Scan (chỉ mục bao mọi cột truy vấn chạm vào còn gọi là covering index).

Tra cứu thường so với Index-Only Scan
Cột truy vấncầnTra cứu chỉ mụcthường (SEARCH)Quay về bảng nềnlấy cột khácKết quảChỉ mục với mọi cột→ Index-Only ScanKhông chuyến quayvề bảng nềnKết quả(USING COVERING INDEX)
Tra cứu chỉ mục thường tìm dòng trong chỉ mục rồi quay lại bảng nền. Nếu mọi cột cần ở trong chỉ mục, truy vấn không bao giờ quay về bảng nền — chỉ mục một mình tạo ra kết quả.
-- Tổng hợp region với chỉ mục chỉ chứa region
-- Cột được tham chiếu (region) hoàn toàn ở trong chỉ mục → không chuyến quay về bảng nền
DROP INDEX IF EXISTS ix_demo;
CREATE INDEX ix_demo ON perf_sales(region);

EXPLAIN QUERY PLAN
SELECT region, COUNT(*)
FROM perf_sales
GROUP BY region;

Hãy tưởng tượng yêu cầu: "Chúng ta muốn tổng doanh số mỗi nhân viên." Truy vấn này chỉ chạm hai cột: emp_idamount. Xây chỉ mục chứa cả hai, và xác nhận kế hoạch đưa ra kết quả chỉ từ chỉ mục, không quay về bảng nền. Xóa và xây lại chỉ mục trong một lần thực thi console để kế hoạch tự đứng vững. (Chạy đúng sẽ làm xuất hiện phần giải thích.)

① Xóa chỉ mục với DROP INDEX IF EXISTS.

② Tạo chỉ mục chứa cả emp_idamount — các cột truy vấn tham chiếu.

③ Dùng EXPLAIN QUERY PLAN trên truy vấn tổng hợp tính tổng amount mỗi emp_id, và xác nhận kế hoạch không bao giờ đọc bảng nền.

SQL Editor

Chạy truy vấn để xem kết quả

Thiếu một cột và bạn quay về bảng nền

Index-Only Scan chỉ xảy ra khi mọi cột truy vấn chạm vào — trong SELECT, WHERE, GROUP BY, vv. — ở trong chỉ mục.

Thiếu một cột và cơ sở dữ liệu phải quay về bảng nền để đọc nó, và USING COVERING INDEX biến mất khỏi kế hoạch.

Ví dụ, với chỉ mục trên (emp_id, amount), viết SELECT emp_id, SUM(amount), region thêm region, không có trong chỉ mục — nên truy vấn quay về bảng nền để lấy nó.

Bỏ một cột và Index-Only Scan hỏng
INDEX (emp_id, amount)Chứa: emp_id, amountSELECT emp_id,SUM(amount)Mọi cột có mặt→ chỉ mục một mình đủSELECT emp_id,SUM(amount), regionregion thiếu→ quay về bảng nền
Nếu mọi cột truy vấn chạm vào ở trong chỉ mục, tất cả nằm trong chỉ mục. Thiếu một và cơ sở dữ liệu quay về bảng nền để đọc cột đó, phá Index-Only Scan.
-- Với chỉ mục trên (region, amount),
-- thêm product vào các cột được tham chiếu phá Index-Only Scan
DROP INDEX IF EXISTS ix_demo;
CREATE INDEX ix_demo ON perf_sales(region, amount);

-- region, SUM(amount) chỉ → bao trọn bởi chỉ mục
EXPLAIN QUERY PLAN
SELECT region, SUM(amount) FROM perf_sales GROUP BY region;

-- Thêm product → không có trong chỉ mục, nên quay về bảng nền
EXPLAIN QUERY PLAN
SELECT region, SUM(amount), MAX(product) FROM perf_sales GROUP BY region;

Dùng cùng chỉ mục, so sánh hai tổng hợp: một có cột được tham chiếu vừa trong chỉ mục, và một thêm một cột không có. Xây chỉ mục composite trên emp_idamount, rồi xem cả hai kế hoạch cạnh nhau.

① Xóa chỉ mục với DROP INDEX IF EXISTS.

② Tạo chỉ mục composite chứa emp_idamount.

③ Hiển thị EXPLAIN QUERY PLAN cho tổng hợp tính tổng amount mỗi emp_id (vừa trong chỉ mục).

④ Sau đó hiển thị EXPLAIN QUERY PLAN cho cùng tổng hợp cộng max của region, và so sánh với ③ để xem kế hoạch thay đổi thế nào (region không có trong chỉ mục).

SQL Editor

Chạy truy vấn để xem kết quả

Giữ Index-Only Scan bằng cách bao cả cột bộ lọc WHERE

SELECT không phải nơi duy nhất cột xuất hiện trong truy vấn của bạn.

Cột bộ lọc WHERE cũng tính là cột truy vấn chạm vào, nên chúng cần ở trong chỉ mục — nếu không bạn vẫn quay về bảng nền.

Gấp tất cả vào một chỉ mục theo thứ tự "cột bộ lọc → cột đầu ra / tổng hợp", và cả việc lọc lẫn lấy giá trị kết thúc trong cùng chỉ mục.

Ví dụ, để lọc với WHERE region = 'East' và tính SUM(amount), đặt cột bộ lọc region trước và cột tổng hợp amount sau: (region, amount).

Chỉ mục thu hẹp về các dòng đích theo region và đọc amount từ cùng chỉ mục, nên không cần chuyến quay về bảng nền.

Gấp cột bộ lọc và cột đầu ra vào một chỉ mục
WHERE region='East'SELECT SUM(amount)Lọc: regionLấy: amountINDEX(region, amount)Lọc theo region vàđọc amount cùng lúcXong không cần bảngCột bộ lọc đếntrước — đó là sự phù hợp
Đặt cột bộ lọc WHERE trước và cột SELECT / tổng hợp sau chúng trong một chỉ mục duy nhất, và cả việc lọc lẫn lấy giá trị kết thúc trong cùng chỉ mục — không chuyến quay về bảng nền.
-- Gấp cột bộ lọc (status) và cột tổng hợp (amount) vào một chỉ mục
DROP INDEX IF EXISTS ix_demo;
CREATE INDEX ix_demo ON perf_sales(status, amount);

EXPLAIN QUERY PLAN
SELECT SUM(amount)
FROM perf_sales
WHERE status = 'pending';

Hãy tưởng tượng yêu cầu: "Chúng ta muốn tổng doanh số cho một khu vực cụ thể." Truy vấn lọc trên region trong WHERE và tính tổng amount. Gấp cột bộ lọc và cột tổng hợp vào một chỉ mục, và xác nhận kế hoạch không bao giờ quay về bảng nền.

① Xóa chỉ mục với DROP INDEX IF EXISTS.

② Tạo chỉ mục composite với cột bộ lọc region trước và cột tổng hợp amount sau.

③ Dùng EXPLAIN QUERY PLAN trên tổng hợp lọc theo region và tính tổng amount, và xác nhận kế hoạch không bao giờ đọc bảng nền.

SQL Editor

Chạy truy vấn để xem kết quả
QUIZ

Kiểm tra kiến thức

Hãy trả lời từng câu hỏi một.

Câu 1Vì sao Index-Only Scan tránh quay về bảng nền?

Câu 2Với chỉ mục trên (emp_id, amount), truy vấn nào phá Index-Only Scan và quay về bảng nền?

Câu 3Với truy vấn lọc bằng WHERE region = 'East' và tính SUM(amount), chỉ mục nào hỗ trợ Index-Only Scan?