索引是資料庫效能的靈魂。MySQL 支援多種索引類型,理解其底層結構 (B+ Tree)、建立時機、失效條件,才能做出正確的索引設計決策。本文深度解析 MySQL 索引機制與實戰應用。
CREATE INDEX idx_name ON users(name);
ALTER TABLE users ADD INDEX idx_name (name);
CREATE TABLE users (id INT, name VARCHAR(50), INDEX idx_name (name));
允許重複、允許 NULL、最基礎索引。
CREATE UNIQUE INDEX uk_email ON users(email);
ALTER TABLE users ADD UNIQUE uk_email (email);
值唯一、允許多個 NULL (MySQL 特性)、可多個。
CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(50));
ALTER TABLE users ADD PRIMARY KEY (id);
ALTER TABLE users ADD INDEX idx_name_city_age (name(10), city, age);
ALTER TABLE articles ADD FULLTEXT ft_content (content);
SELECT * FROM articles WHERE MATCH(content) AGAINST('關鍵字');
ALTER TABLE geom ADD SPATIAL INDEX sp_idx (location);
=, >, <, >=, <=, BETWEEN, IN, LIKE 'prefix%')ON t1.id = t2.id)| 場景 | SQL 範例 | 原因 |
|---|---|---|
| 函數/運算在索引列 | WHERE YEAR(dt) = 2024 | 索引存原始值,函數破壞有序性 |
| 隱式類型轉換 | WHERE varchar_col = 123 | MySQL 轉換欄位值,等同函數操作 |
| LIKE 以 % 開頭 | WHERE name LIKE '%abc' | B+ Tree 只支援前綴匹配 |
| OR 條件欄位無索引 | WHERE a=1 OR b=2 (b 無索引) | MySQL 5.6+ Index Merge 有條件支援,但通常全掃 |
| 組合索引違反最左前綴 | WHERE b=2 (索引 a,b) | 缺少最左列 a |
| IS NULL / IS NOT NULL | WHERE col IS NULL | 5.6+ 可用索引,但選擇性通常極低 |
| NOT IN / NOT EXISTS | WHERE id NOT IN (subquery) | 難以利用索引,改寫 LEFT JOIN IS NULL |
| 字元集/校對規則不匹配 | JOIN 兩表欄位 charset 不同 | 隱式轉換導致索引失效 |
SHOW INDEX FROM users;
-- 或
SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 'users';
ANALYZE TABLE users; -- 更新統計資訊
SHOW INDEX FROM users; -- Cardinality 欄位查看基數
SELECT * FROM sys.schema_unused_indexes;
SELECT * FROM sys.schema_redundant_indexes;
-- MySQL 5.6+ 預設線上
ALTER TABLE big_table ADD INDEX idx_col (col), ALGORITHM=INPLACE, LOCK=NONE;
-- 強制複製表 (舊版/特定操作)
ALTER TABLE big_table ADD INDEX idx_col (col), ALGORITHM=COPY;
觸發器/影子表機制,零停機建立索引,大表必備工具。
索引是把雙面刃:用對是效能倍增器,用錯是寫入殺手。掌握 B+ Tree 原理、最左前綴、失效場景、監控工具,建立「索引設計 → 驗證 → 維護」閉環,才能讓索引持續創造價值。