索引是關係型數據庫性能的基石,但「索引越多越好」是危險誤區。本文系統梳理索引優缺點、何時創建/不創建、MySQL 創建語法、五大失效場景、監控指標與最佳實踐清單。
WHERE 條件列。JOIN ON 的外鍵列。>, <, BETWEEN) 的列,索引天然有序。ORDER BY/GROUP BY 的列,避免 filesort。is_deleted、sex、status (除非組合索引前綴)。TEXT、BLOB、LONGTEXT 等大字段 (可建前綴索引 col(20),但 5.7+ 支援全文索引更合適)。-- 普通索引
CREATE INDEX idx_name ON tbl(col);
ALTER TABLE tbl ADD INDEX idx_name (col);
-- 唯一索引
CREATE UNIQUE INDEX uk_name ON tbl(col);
ALTER TABLE tbl ADD UNIQUE INDEX uk_name (col);
-- 主鍵 (建表時)
CREATE TABLE tbl (id INT PRIMARY KEY, ...);
ALTER TABLE tbl ADD PRIMARY KEY (id);
-- 全文索引 (5.6+ InnoDB)
CREATE FULLTEXT INDEX ft_name ON tbl(col);
ALTER TABLE tbl ADD FULLTEXT INDEX ft_name (col);
-- 多列/聯合索引 (遵循最左前綴)
CREATE INDEX idx_a_b_c ON tbl(a, b, c);
WHERE a=1 OR b=2,若 a 有索引 b 無,全表掃描。解決:a,b 都建索引或改 UNION ALL。INDEX(a,b,c),查詢 WHERE b=1 或 WHERE c=1 不走索引。WHERE name LIKE '%abc%' 不走索引;LIKE 'abc%' 可走。WHERE phone = 13800138000 (phone 是 VARCHAR),MySQL 會轉換列值導致索引失效。解決:WHERE phone = '13800138000'。SELECT *、調整 optimizer_switch。SHOW STATUS LIKE 'Handler_read%';
-- Handler_read_key: 索引讀取次數 (越高越好)
-- Handler_read_rnd_next: 全表掃描次數 (越低越好)
WHERE 等值條件列 → ORDER BY 列 → SELECT 列 (覆蓋)。DROP 未用索引 (sys.schema_unused_indexes 視圖)。INDEX(a,b,c) 覆蓋 SELECT a,b,c FROM t WHERE a=1,Extra 顯示 Using index。ANALYZE TABLE 更新統計信息,防止優化器誤判。索引設計本質是「空間換時間」與「寫換讀」的權衡。沒有完美索引,只有適合當前查詢負載的索引。建立基線 → 慢查詢分析 → 針對性加索引 → 驗證回歸 → 定期清理,形成閉環。