索引是查詢性能的核心。MySQL (InnoDB) 支持多種索引類型,各有適用場景與限制。本文系統梳理六大類索引特性、創建語法、選型決策樹、常見誤區。
CREATE INDEX idx_name ON `table` (`col`);
ALTER TABLE `table` ADD INDEX idx_name (`col`);
CREATE UNIQUE INDEX uk_email ON `users` (`email`);
ALTER TABLE `users` ADD UNIQUE KEY uk_email (`email`);
PRIMARY KEY (`id`)
ALTER TABLE `table` ADD PRIMARY KEY (`id`);
BIGINT UNSIGNED NOT NULL AUTO_INCREMENT (單調遞增,頁分裂少,二級索引小)。CREATE INDEX idx_a_b_c ON `table` (`a`, `b`, `c`);
SELECT a,b FROM table WHERE a=1 AND b=2 直接走索引掃描,無回表。CREATE FULLTEXT INDEX ft_content ON `articles` (`title`, `body`);
ALTER TABLE `articles` ADD FULLTEXT INDEX ft_content (`title`, `body`);
SELECT * FROM articles WHERE MATCH(title,body) AGAINST('關鍵詞' IN NATURAL LANGUAGE MODE);。ft_min_word_len (默認 4) 影響短詞搜索。ALTER TABLE `geo` ADD SPATIAL INDEX idx_location (`location`);
GEOMETRY 類型 (Point, Polygon 等),R 樹結構。MBRContains, ST_Distance 等空間關係查詢。-- 長字串欄位只索引前綴,節省空間
CREATE INDEX idx_email_prefix ON `users` (`email`(10));
-- 選擇長度使區分度接近完整欄位
SELECT COUNT(DISTINCT LEFT(email,10))/COUNT(*) FROM users; -- 目標 > 0.9
| 誤區 | 後果 | 正確做法 |
|---|---|---|
| 為每個欄位建單列索引 | 寫入放大、優化器選錯索引、空間浪費 | 分析慢查詢,建復合索引覆蓋高頻 SQL |
| 復合索引順序隨意 | 無法命中索引、掃描大量行 | 區分度高在左,範圍列在右 |
| WHERE 條件用函數/表達式 | 索引失效 (如 WHERE YEAR(date)=2024) | WHERE date >= '2024-01-01' AND date < '2025-01-01' |
| 隱式類型轉換 | 索引失效 (如 varchar 欄位比較數字) | 應用層保證類型一致,或 CAST |
| 過度索引 (單表 > 5-6 個) | INSERT/UPDATE/DELETE 明顯變慢 | 定期 sys.schema_unused_indexes 清理無用索引 |
| 以為全文索引能替代 Like | 中文分詞不準、維護成本高 | 專業搜索上 Elasticsearch/OpenSearch |
-- 查看表索引
SHOW INDEX FROM `table`;
-- 分析未使用索引 (sys schema, 5.7+)
SELECT * FROM sys.schema_unused_indexes;
-- 分析索引基數
ANALYZE TABLE `table`;
-- 強制/忽略索引 (調試用)
SELECT * FROM `table` FORCE INDEX (idx_name) WHERE ...;
SELECT * FROM `table` IGNORE INDEX (idx_name) WHERE ...;