問題如下:有一個表,總行數爲21萬,其中只有一個組合主鍵索引 primary key (channel_app_id, content_app_id)
create table t_channel_apply
(
channel_app_id varchar(64) default '' not null comment '渠道方appid',
content_app_id varchar(64) default '' not null comment '內容方appid',
apply_state tinyint(2) default 0 not null comment
created_at timestamp default '0000-00-00 00:00:00' not null comment '創建時間',
updated_at timestamp default CURRENT_TIMESTAMP not null comment '更新時間,有修改自動更新',
primary key (channel_app_id, content_app_id)
)
comment '渠道申請信息表';
我的查詢語句是,只用到了content_app_id
select count(content_app_id) from `t_channel_apply` where `content_app_id` = 'xxx'
如我們周知,mysql的組合索引都是左匹配的原則,即假如組合索引(a,b,c)
a,
a,b
a,b,c
c,b,a
c,a,b
b,a
...
//左匹配並且因爲索引位置可以隨意替換,故以上都會用到索引
b,c
//如果不能左匹配就無法使用索引
但我 explain select count(content_app_id) from t_channel_apply
where content_app_id
= ‘xxx’,發現這個語句竟然用到了索引,這個真是顛覆了我的認知
ok,開始慢慢分析
首先我注意到,不管我的content_app_id查詢值是什麼,rows都不會變,固定是86548,這個奇怪的數字
根據以往的知識 explain 中的 rows 的意思是mysql預估要得到結果要查詢的行數,然後纔會真正執行sql語句,所以這個值只能做參考。
然後我嘗試更改語句來對比。
使用 select count(apply_state) from t_channel_apply
where content_app_id = ‘xxx’ and apply_state = 0;
使用 select count(content_app_id) from t_channel_apply
where apply_state = 0;,
使用 select count(apply_state) from t_channel_apply
where content_app_id = ‘xxx’;,
以上語句都會全表查找,所以就想到查詢條件和查詢字段都是索引的情況就會使用到不就符合了覆蓋索引的條件嗎?
所以得出了結論,就是即使組合索引只用了一部分也能用上索引是對的,前提是符合覆蓋索引的條件
所以可以得出 86548 其實就是索引的行數,mysql預估的時候其實預估查詢索引的行數,雖然真正運行並不準確
ps:
在嘗試查詢中,我得到了一個結果是extra:Impossible WHERE noticed after reading const tables
根據主鍵查詢或者唯一性索引查詢,如果這條數據沒有的話,它會全表掃描,
然後得出一個結論,該數據不在表中。
對於高併發的庫來說,這條數據,會讓負載特別的高。
https://yq.aliyun.com/articles/393774