Trung bình Database

Database Index - Biến Full Scan Thành Tra Cứu Tức Thì

Coi vì sao query hổng có index phải quét từng dòng, index biến nó thành tra cứu lẹ làng cỡ nào, và cách đọc EXPLAIN để phân biệt.

08 Th07, 2026 3 phút 1,850 Lượt xem 4 Khối code
Sơ đồ
flowchart TD Q["Query: WHERE email = ?"] --> D{Index on email?} D -->|No| S[Full table scan: read every row - O n] D -->|Yes| I[B-tree lookup: jump straight to matches - O log n] S --> R1[Slow, and gets worse as the table grows] I --> R2[Fast and scales] style S fill:#fee2e2,stroke:#ef4444 style I fill:#dcfce7,stroke:#22c55e

Database Index - Biến Full Scan Thành Tra Cứu Tức Thì

Câu query chạy mượt re với 1.000 dòng, nhưng tới 1.000.000 dòng là bò luôn. Lý do thường gặp: database đang làm full table scan - quét hết từng dòng để tìm mấy dòng mình cần. Index chính là thứ giải quyết chuyện này.

Không có index: quét hết bảng

SELECT * FROM users WHERE email = '[email protected]';

Không có index trên email, engine phải đọc từng dòng rồi so sánh email. Bảng lớn thì đây là công việc O(n) - càng nhiều dòng càng lâu.

Có index: tra cứu tức thì

CREATE INDEX idx_users_email ON users (email);

Index là cấu trúc đã sắp xếp sẵn (thường là B-tree). Engine giờ đi thẳng tới đúng dòng cần tìm với độ phức tạp khoảng O(log n) - chỉ đọc vài lần thay vì cả triệu lần.

Đọc plan bằng EXPLAIN

EXPLAIN SELECT * FROM users WHERE email = '[email protected]';
  • type = ALL (kèm "Using where") nghĩa là full scan - chậm.
  • type = ref hoặc const có liệt kê key nghĩa là đang xài index - ngon.

Composite index đi theo quy tắc trái-sang-phải

CREATE INDEX idx_orders_user_status ON orders (user_id, status);

Cái này giúp cho WHERE user_id = ?WHERE user_id = ? AND status = ?, nhưng không giúp cho WHERE status = ? đứng một mình - query phải xài prefix bên trái của mấy cột đã đánh index.

Khi nào index KHÔNG giúp được gì

  • WHERE YEAR(created_at) = 2026 - bọc cột trong hàm là index vô dụng liền. Xài range thay thế: created_at >= '2026-01-01' AND created_at < '2027-01-01'.
  • LIKE '%term' có dấu % ở đầu thì không xài được index thường.
  • Cột có độ chọn lọc thấp (như kiểu boolean) - đôi khi quét hết còn rẻ hơn xài index.

Rút gọn lại

  • Không có index là full scan (O(n)); có index đúng chỗ là tra cứu tức thì (O(log n)).
  • Đánh index mấy cột hay filter, join, sort - đừng đánh hết mọi cột (index tốn chi phí ghi và lưu trữ).
  • Xài EXPLAIN để chắc chắn index có thật sự được dùng.
  • Giữ filter sargable: đừng bao giờ bọc cột đã đánh index trong hàm.
Thử thách tương tác

Thử thách

Luyện tập ngay điều vừa học. Viết lời giải, mở gợi ý nếu bí.

Ngôn ngữPHP

Code khởi tạo

php
SELECT * FROM orders
WHERE YEAR(created_at) = 2026;

Lời giải của bạn

Lời giải · php
SELECT * FROM orders
WHERE created_at >= '2026-01-01'
  AND created_at <  '2027-01-01';

Cùng chủ đề Database