索引設計是查詢性能的關鍵。很多開發者習慣為每個查詢列建單列索引,實則聯合索引往往更高效。本文通過對比實驗,深度解析兩類索引的優化器行為差異。
CREATE TABLE test (
id INT NOT NULL,
last_name CHAR(30) NOT NULL,
first_name CHAR(30) NOT NULL,
PRIMARY KEY (id),
INDEX idx_last_name (last_name),
INDEX idx_first_name (first_name)
);
CREATE TABLE test (
id INT NOT NULL,
last_name CHAR(30) NOT NULL,
first_name CHAR(30) NOT NULL,
PRIMARY KEY (id),
INDEX idx_name (last_name, first_name)
);
(last_name, first_name) 拼接-- 數據分布:last_name='Widenius' 2944 行,其中 first_name='Michael' 10 行
| 查詢 | 單列索引表 | 聯合索引表 |
|---|---|---|
WHERE last_name='Widenius' | 使用 idx_last_name,rows=2944 | 使用 idx_name,rows=2944 |
WHERE last_name='Widenius' AND first_name='Michael' | 選擇區分度高的單列索引,另一列回表過濾 | 使用 idx_name,rows=10,無回表、無排序 |
WHERE first_name='Michael' | 使用 idx_first_name | 無法使用索引(非最左列) |
WHERE last_name='Widenius' OR first_name='Michael' | 可能 Index Merge 或全表掃描 | 無法使用索引 |
INDEX(user_id, create_time) 而非反序MySQL 5.0+ 支持 Index Merge(union/intersection/sort-union),如:
WHERE last_name='Widenius' OR first_name='Michael'
-- 可能使用 idx_last_name UNION idx_first_name
但實測性能通常不如聯合索引,且不可控,不建議依賴。
SHOW INDEX FROM test;
EXPLAIN SELECT * FROM test WHERE last_name='Widenius' AND first_name='Michael';
正確選擇聯合索引而非堆疊單列索引,是索引設計從入門到進階的分水嶺。