Trung bình Database

Database Indexes: Turn a Full Scan Into an Instant Lookup

See why a query without an index scans every row, how an index turns it into a fast lookup, and how to read EXPLAIN to tell the difference.

08 Th07, 2026 2 phút 27 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 Indexes: Turn a Full Scan Into an Instant Lookup

A query that feels instant on 1,000 rows can crawl on 1,000,000. The usual reason: the database is doing a full table scan — reading every row to find the few you asked for. An index fixes that.

Without an index: a full table scan

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

With no index on email, the engine reads every row and compares email. On a large table that is O(n) work.

With an index: a lookup

CREATE INDEX idx_users_email ON users (email);

An index is a sorted structure (usually a B-tree). The engine now navigates straight to the matching rows in about O(log n) — a handful of reads instead of millions.

Read the plan with EXPLAIN

EXPLAIN SELECT * FROM users WHERE email = '[email protected]';
  • type = ALL (and "Using where") means a full scan — slow.
  • type = ref or const with a key listed means the index is used — good.

Composite indexes follow a left-to-right rule

CREATE INDEX idx_orders_user_status ON orders (user_id, status);

This helps WHERE user_id = ? and WHERE user_id = ? AND status = ?, but not WHERE status = ? on its own — a query must use a left prefix of the indexed columns.

When an index does NOT help

  • WHERE YEAR(created_at) = 2026 — wrapping the column in a function defeats the index. Use a range instead: created_at >= '2026-01-01' AND created_at < '2027-01-01'.
  • LIKE '%term' with a leading wildcard cannot use a normal index.
  • Very low-selectivity columns (like a boolean) — a scan is sometimes cheaper than the index.

Key takeaways

  • No index means a full scan (O(n)); the right index means a lookup (O(log n)).
  • Index the columns you filter, join and sort on — not every column (indexes cost writes and storage).
  • Use EXPLAIN to confirm the index is actually used.
  • Keep filters sargable: never wrap an indexed column in a function.
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í.

Đề bài

This query filters on YEAR(created_at), which wraps the indexed column in a function and forces a full table scan even when created_at is indexed. Rewrite it as a sargable date-range query that can actually use the index.

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';