MySQL中in到底走不走索引?

2021-10-10 08:52:53 字數 4017 閱讀 5905

mysql中explain關鍵字可以模擬mysql優化器執行sql語句,是乙個可以很好的分析sql語句或表結構的效能瓶頸。

explain的使用方法:explain + sql語句,下面我們先來執行下explain語句

explain select * from `user` where created_time > "2020-03-08";
執行結果如下:

可以看到有幾個返回引數:id、select_type、table、partitions、type、possible_keys、key、key_len、ref、rows、filtererd、extra。

下面先介紹下這些引數的含義

id // 選擇識別符號

select_type // 表示查詢的型別

table // 輸出結果集的表

partitions // 匹配的分割槽

type // 表示表的連線型別,

possible_keys // 表示查詢時,可能使用的索引

key // 表示實際使用的索引

key_len // 索引欄位的長度

ref // 列與索引的比較

rows // 掃瞄出的行數(估算的行數)

filtered // 按表條件過濾的行百分比

extra // 執**況的描述和說明

我們把比較重要的引數提取出來進行詳細講解一下:

表示連線型別,型別有all、index、range、 ref、eq_ref、const、system、null,這幾種型別從左到右,效能越來越高。一般乙個好的sql語句至少要達到range級別。all級別應當杜絕

all:全表掃瞄,應當避免該型別

index:索引全域性掃瞄,index與all區別為index型別只遍歷索引樹

range:檢索索引一定範圍的行

ref:非唯一性索引掃瞄,返回匹配某個單獨值的所有行

eq_ref:唯一索引掃瞄,對於每個索引鍵,表中只有一條記錄與之匹配。常見主鍵或唯一索引掃瞄

const:表示通過一次索引就找到了結果,常出現於primary key或unique索引

system:system是const型別的特例,當查詢的表只有一行的情況下,使用system

null:mysql在優化過程中分解語句,執行時甚至不用訪問表或索引,是最高的登記

表示實際使用到的索引,如果為null,則沒有使用索引

表示使用索引長度

表示根據sql情況,預估表的掃瞄行數

表示詳細說明,注意該值包含十分重要的資訊。一般該列存在下列值,常見的不太友好的值有:using filesort, using temporary

using where // 表示不用讀取表中所有資訊,僅通過索引就可以獲取所需資料,即使用列覆蓋索引

using temporary // 表示需要使用臨時表來儲存結果集,常見於排序和分組查詢,如:group by ; order by

using filesort // 表示無法利用索引完成的排序

using join buffer // 表示使用了連線快取,如果出現了這個值,建議根據查詢的具體情況可能需要新增索引來改進能。

impossible where // 表示where語句會一直false,導致沒有符合條件的行(通過收集統計資訊不可能存在結果)

select tables optimized away // 這個值意味著sql優化到不能在優化了

no tables used // query語句中使用from dual 或不含任何from子句

好了,我們對explain執行計畫做了乙個基本的介紹,下面我們來看看in到底會不會走索引

建立表如下:

create table `test` (

`id` int not null auto_increment,

`name` varchar(120) default null comment '姓名',

`age` int default null,

primary key (`id`),

key `idx_name` (`name`)

) engine=innodb default charset=utf8 comment='測試表';

插入資料

insert into `test`.`test`(`id`, `name`, `age`) values (1, 'xiaoming', 18);
執行explain執行計畫

explain select * from test where name  in ("lisi")
檢視結果

可以看到in確實走了所以 idx_name,那是不是in永遠都會走索引呢?

我們通過儲存過程插入10000條資料

delimiter //

drop procedure if exists inserttestdata;

create procedure inserttestdata () begin

declare i int;

set i = 0;

while i < 10000 do

insert into test(`name`, `age`) values (concat('xiaoming', concat( i, '' )), 18);

set i = i + 1;

end while;

end //

call inserttestdata();

delimiter ;

此時我們再看下是不是in繼續走索引

explain select * from test where name  in ("lisi","xiaoming1")
發現依舊走索引

此時我們再插入2000條"lisi"這樣的資料

delimiter //

drop procedure if exists inserttestdata;

create procedure inserttestdata () begin

declare i int;

set i = 0;

while i < 2000 do

insert into test(`name`, `age`) values ('lisi', 18);

set i = i + 1;

end while;

end //

call inserttestdata();

delimiter ;

執行依舊in走索引,那是不是意味著in一定走索引呢?當我們再繼續執行2次插入2000條"lisi",即資料庫有6000條name=「lisi」的資料時,神奇的發現in並不走索引了,如下圖

in通常是走索引的,當in後面的資料在資料表中超過30%

(上面的例子的匹配資料大約6000/16000 = 37.5%)的匹配時,會走全表掃瞄,即不走索引,因此in走不走索引和後面的資料有關係。 附:

mysql中explain用法和結果分析(詳解)-mysql教程-php中文網

mysql 索引 大於等於 走不走索引 最左字首

你可以認為聯合索引是闖關遊戲的設計 例如你這個聯合索引是state city zipcode 那麼state就是第一關 city是第二關,zipcode就是第三關 你必須匹配了第一關,才能匹配第二關,匹配了第一關和第二關,才能匹配第三關 你不能直接到第二關的 索引的格式就是第一層是state,第二層...

mysql不走索引總結

在mysql查詢語句中,總會發現明明已經建立了查詢字段索引,可是卻沒有用到,這是因為在mysql中有些查詢語句是用不到索引的,總結如下,以供大家分享。1.like語句 2.列型別為字串型別,查詢時沒有用單引號引起來 3.在where查詢語句中使用表示式 4.在where查詢語句中對字段進行null值...

Mysql中哪些Sql不走索引

select sname from stu where age 10 30 不會使用索引,因為所有索引列參與了計算 select sname from stu where left date 4 1990 不會使用索引,因為使用了函式運算,原理與上面相同 select from houdunwang...