mysql 索引實踐(二) 聯合索引
#emp_no PRIMARY
#first_name,last_name,gender idx_first_name_last_name
show index from employees
最左匹配:
不是指的順序,而是where 中將根據聯合索引的建立順序,去檢索當前SQL能用到該聯合索引到哪一步。
first_name,last_name,gender :可匹配 (first_name)、(first_name,last_name)、(first_name,last_name,gender)
#ref
explain select * from employees where first_name = 'Parto1'
#ref
#Using where
explain select * from employees where first_name = 'Parto1' and birth_date = '1953-09-02'
#ref
#Using where
explain select * from employees where first_name = 'Parto1' and birth_date != '1953-09-02'
#ALL
#Using where
explain select * from employees where first_name != 'Parto1'
若聯合索引的第一個欄位為不等值查詢,則該SQL一定不走該聯合索引。
此時,可以發現是否使用和SQL中欄位的順序無關
此時,當前SQL能用到該聯合索引 first_name,last_name
#ref
explain select * from employees where first_name = 'Parto1' and last_name = 'Parto1'
#ref
explain select * from employees where last_name = 'Parto1' and first_name = 'Parto1'
#ref
#Using where
explain select * from employees where birth_date = '1953-09-02' and first_name = 'Parto1' and last_name = 'Parto1'
explain select * from employees where first_name = 'Parto1' and birth_date = '1953-09-02' and last_name = 'Parto1'
explain select * from employees where first_name = 'Parto1' and last_name = 'Parto1' and birth_date = '1953-09-02'
explain select * from employees where first_name = 'Parto1' and last_name = 'Parto1' and birth_date != '1953-09-02'
explain select * from employees where first_name = 'Parto1' and last_name = 'Parto1' and birth_date is not null
此時,當前SQL能用到該聯合索引 first_name
#range
#Using index condition
explain select * from employees where first_name = 'Parto1' and last_name != 'Parto1'
explain select * from employees where first_name = 'Parto1' and last_name != 'Parto1' and gender = 'M'
explain select * from employees where first_name = 'Parto1' and last_name != 'Parto1' and gender != 'M'
explain select * from employees where first_name = 'Parto1' and last_name is not null and gender is not null
explain select * from employees where first_name = 'Parto1' and last_name != 'Parto1' and birth_date = '1953-09-02'
explain select * from employees where first_name = 'Parto1' and last_name != 'Parto1' and birth_date != '1953-09-02'
此時,當前SQL不能用到該聯合索引
#ALL
#Using where
explain select * from employees where first_name != 'Parto1' and last_name = 'Parto1'
explain select * from employees where first_name != 'Parto1' and last_name = 'Parto1' and gender = 'M'
explain select * from employees where first_name != 'Parto1' and last_name = 'Parto1' and birth_date = '1953-09-02'
總之, 對於聯合索引,會將SQL中的欄位按照索引的順序去匹配,若某一欄位未匹配上,或者該欄位查詢為不等值查詢,該索引將只執行到該欄位之前,在此之後的欄位,即使匹配且為等值查詢,也將不再繼續進行匹配了。
因此,如果若第一個欄位就匹配不上或者該欄位為不等值查詢,則一定為全表掃描。
例如,(A,B,C) 如果B 缺失或者B為不等值查詢,則索引將只執行到A,此時B,C不執行。
不滿足所有列均為索引
#ALL
#Using where
explain select * from employees where first_name = 'Parto1' or last_name = 'Parto1'
explain select * from employees where first_name = 'Parto1' or birth_date = '1953-09-02'
滿足所有列均為索引
#index_merge
#Using union(idx_first_name_last_name,PRIMARY); Using where
explain select * from employees where first_name = 'Parto1' and last_name = 'Parto1' and gender = 'M' or emp_no = 10005
不滿足所有列均為索引
#ALL
#Using where
explain select * from employees where first_name = 'Parto1' and last_name = 'Parto1' and gender = 'M' or birth_date = '1953-09-02'
#使用OR連線時:
#1.1 當所有的列均為索引,且為等值查詢,仍將採用index_merge 進行查詢
#1.2 若有一列不是索引,此時將全表掃描;
#1.3 若至少有一列的索引不是等值查詢,此時將全表掃描