我們都知道MySQL在查詢時底層會進行索引的優化,假設有兩個普通索引,且where 后面也根據這兩個普通索引查詢數據,那么執行查詢語句時會使用到那個索引?
為了方便演示,新建users表,新建idx_name、idx_city這兩個普通索引如下:
CREATE TABLE users (id INT PRIMARY KEY,name VARCHAR(50) ,age INT,city VARCHAR(50) ,INDEX idx_name (name),INDEX idx_city (city)
) DEFAULT CHARSET=utf8mb4i;
INSERT INTO users (id, name, age, city)
VALUES(1, '張三', 25, '北京'),(2, '李四', 30, '上海'),(3, '王五', 40, '廣州'),(4, '趙六', 35, '深圳'),(5, '張三', 28, '上海');
1)根據單個索引查詢
根據name 查詢數據時,如下圖key = idx_name ,即走了idx_name的索引
explain select * from users where name = '張三';
根據city查詢數據時,如下圖key = idx_city ,即走了idx_city的索引
2)根據多個普通索引查詢
示例1:
根據name和city查詢,并且name和city能夠定位到一條數據
explain select * from users where name = '張三' and city = '上海';
即使沒有復合索引,優化器也可以選擇使用索引合并策略。它可以使用 idx_name
索引定位滿足 name = '張三'
的行,然后使用 idx_city
索引在之前的結果集上進行進一步篩選,以滿足 city = '上海'
的條件。
示例2:
根據name和city查詢,并且單獨查詢name時,name = ‘張三’ 有兩條記錄,單獨查詢city時,city=‘廣州’ 有一條記錄
explain select * from users where name = '張三' and city = '廣州';
此時優化器會走idx_city索引,這是因為如果走idx_name索引要查詢兩次,根據idx_city一次查詢就能定位到具體的數據,因此此處優化器采用idx_city作為索引。
同樣執行如下SQL也是走的idx_city的索引,因為city='北京’的記錄只有一條
explain select * from users where name = '張三' and city = '北京';
再來看看下面的這個SQL語句,會走那個索引呢?
explain select * from users where name = '李四' and city = '上海';
如上圖,當根據name = '李四’查詢出來數據只有一條、city='上海’有兩條數據,最終結果走的是idx_name索引
示例3:
explain select * from users where city = '廣州' and name = '趙六';explain select * from users where name = '趙六' and city = '廣州';
上面兩個SQL語句查詢執行計劃時發現,兩條語句的查詢計劃是一致的,都是直接走idx_name索引,不管where條件后面name和city的先后順序
原因是,如上圖執行計劃中possiblie_keys = idx_name,idx_city。因為idx_name 先創建,所以優化器會先判斷是否走了idx_name索引,name=‘趙六’ 剛好檢索出一條記錄
實例4
explain select * from users where city = '廣州' and name = '張三';
這個時候走的是idx_city的索引,不管where條件后面name和city的順序。
案例5
explain select * from users where city = '廣州' and name = '王五';
explain select * from users where name = '王五' and city = '廣州' ;
以上兩個SQL都走了idx_name的索引,和案例1有一些區別,案例1中,name = ‘張三’ 或者 city = '上海’都能查詢多多行數據,如果使用聯合索引的話效率更高。案例5中,由于根據idx_name就能把這一行的數據給定位到了,因此采用idx_name索引就能滿足。
以上都是MySQL優化器自動選擇索引,那如果我們想強制使用自己的索引可以使用 force index,具體如下
查詢name = ‘張三’ 、city = '廣州’的數據,我們通過查詢計劃得知走的是idx_city索引。
explain select * from users where name = '張三' and city = '廣州';
如果我們強制使用idx_name索引,看看效果,發現已經強制使用idx_name索引