Mysql的索引使用、索引失效的情況

索引使用

索引是數據庫優化最常用也是最重要的手段之一, 通過索引通常可以幫助用戶解決大多數的MySQL的性能優化問題。

一、驗證索引提升的效率

首先我們先不加索引:
在這裏插入圖片描述
在這裏插入圖片描述
查詢時間是2秒多,現在我們加上索引並查看:

create index idx_test_agency on test(agency);
show index from test;

在這裏插入圖片描述
這裏發現一個問題,創建索引花了10多秒,是因爲原本就有300w條數據,所以數據庫需要去重建底層的索引結構。
再次查詢:只用了0.03s
在這裏插入圖片描述
然後分析這條語句:
在這裏插入圖片描述
使用了剛纔創建的索引,效率提升了很多。

二、索引的使用

(1)創建表和索引

create table `tb_seller` (
	`sellerid` varchar (100),
	`name` varchar (100),
	`nickname` varchar (50),
	`password` varchar (60),
	`status` varchar (1),
	`address` varchar (100),
	`createtime` datetime,
    primary key(`sellerid`)
)engine=innodb default charset=utf8mb4;

# 插入數據
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('alibaba','阿里巴巴','阿里小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('baidu','百度科技有限公司','百度小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('huawei','華爲科技有限公司','華爲小店','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('itcast','傳智播客教育科技有限公司','傳智播客','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('itheima','黑馬程序員','黑馬程序員','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('luoji','羅技科技有限公司','羅技小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('oppo','OPPO科技有限公司','OPPO官方旗艦店','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('ourpalm','掌趣科技股份有限公司','掌趣小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('qiandu','千度科技','千度小店','e10adc3949ba59abbe56e057f20f883e','2','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('sina','新浪科技有限公司','新浪官方旗艦店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('xiaomi','小米科技','小米官方旗艦店','e10adc3949ba59abbe56e057f20f883e','1','西安市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('yijia','宜家家居','宜家家居旗艦店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');

# 創建一個複合索引
create index idx_seller_name_sta_addr on tb_seller(name,status,address);

(2)索引失效的情況以及避免方式

1. 全值匹配 ,對索引中所有列都指定具體值。

該情況下,索引生效,執行效率高,:

explain select * from tb_seller where name='小米科技' and status='1' and address='北京市';

在這裏插入圖片描述
可以看到索引已經生效。

2. 最左前綴法則

如果索引了多列,要遵守最左前綴法則。指的是查詢從索引的最左前列開始,並且不跳過索引中的列。

explain select * from tb_seller where name='小米科技';
explain select * from tb_seller where name='小米科技' and status='1';
explain select * from tb_seller where name='小米科技' and status='1' and address='北京市';

在這裏插入圖片描述

可以看到,三種情況索引都生效了,現在測試一下索引失效的情況,違背了最左前綴法則:

explain select * from tb_seller where status='1' and address='北京市';
explain select * from tb_seller where name='小米科技'and address='北京市';

在這裏插入圖片描述
可以發現,跳過中間的索引時,最左邊的索引還是會生效,但是另外一個就不會生效了。

還有一種情況:當三個索引條件都存在時,與順序無關,都能生效;

explain select * from tb_seller where status='1' and address='北京市' and name='小米科技';
explain select * from tb_seller where status='1' and name='小米科技' and address='北京市';

在這裏插入圖片描述

3. 範圍查詢右邊的列,不能使用索引 。

explain select * from tb_seller where name='小米科技' and status > '1' and address='北京市';

在這裏插入圖片描述
這裏可以發現:當status是個範圍查詢的時候,右邊的索引就失效了;

4. 不要在索引列上進行運算操作, 索引將失效。

explain select * from tb_seller where substring(name, 3, 2) = '科技';

在這裏插入圖片描述
當我們在截取字段時,做了個運算導致了索引失效了;

5. 字符串不加單引號,造成索引失效。

explain select * from tb_seller where name='小米科技' and status = 1 and address='北京市';

在這裏插入圖片描述
我們可以看到,當status後面沒有加上單引號時,自己本身失效了,右邊的索引也失效了。
由於,在查詢時,沒有對字符串加單引號,MySQL的查詢優化器,會自動的進行類型轉換,造成索引失效。

6. 儘量使用覆蓋索引,避免select *

explain select name, status, address from tb_seller where name='小米科技' and status = '1' and address='北京市';

explain select name, status, address, password from tb_seller where name='小米科技' and status = '1' and address='北京市';

在這裏插入圖片描述
雖然索引都用上了,但是第一條sql的執行效率會高於第二條;

TIP : 
	
    using index :使用覆蓋索引的時候就會出現

    using where:在查找使用索引的情況下,需要回表去查詢所需的數據

    using index condition:查找使用了索引,但是需要回表查詢數據

    using index ; using where:查找使用了索引,但是需要的數據都在索引列中能找到,所以不需要回表查詢數據

7. 用or分割開的條件, 如果or前的條件中的列有索引,而後面的列中沒有索引,那麼涉及的索引都不會被用到。

explain select * from tb_seller where name='黑馬程序員' or createtime = '2088-01-01 12:00:00';

在這裏插入圖片描述
這裏索引失效了,如果使用and則有索引的生效。

8. 以%開頭的Like模糊查詢,索引失效。

如果僅僅是尾部模糊匹配,索引不會失效。如果是頭部模糊匹配,索引失效。

explain select * from tb_seller where name like '黑馬程序%';
explain select * from tb_seller where name like '%黑馬程序%';

在這裏插入圖片描述
前者不失效,但是後者失效了,解決這個問題的辦法就是進行索引覆蓋。

explain select name from tb_seller where name like '%黑馬程序%';

在這裏插入圖片描述

9. 如果MySQL評估使用索引比全表更慢,則不使用索引。

create index idx_address on tb_seller(address);
explain select * from tb_seller where address = '北京市';
explain select * from tb_seller where address = '西安市';

在這裏插入圖片描述
首先是爲地址這個字段增加索引,然後進行兩個地方的查詢,然後發現北京市沒有使用索引而西安市則是使用了索引。
我們查看錶信息看看:
在這裏插入圖片描述
發現只有一條記錄是西安市,其他全是北京市,所以數據庫在全表掃描的時候會放棄效率更慢的索引查找方式。

10. is NULL , is NOT NULL 有時索引失效。

explain select * from tb_seller where address is not null;
explain select * from tb_seller where address is null;

在這裏插入圖片描述
但是在上述一樣的情況下:如果is null 的全局掃描更快,也既爲空數據多的時候,會進行全局掃描,會放棄索引的方式

11. in 走索引, not in 索引失效。

 explain select * from tb_seller where name not in ('阿里巴巴','小米科技');
 explain select * from tb_seller where name in ('阿里巴巴','小米科技');

在這裏插入圖片描述

12. 單列索引和複合索引

儘量使用複合索引,而少使用單列索引 。

create index idx_name on tb_seller(name);
explain select * from tb_seller where name = "阿里巴巴";

在這裏插入圖片描述
首先爲name創建單列索引,然後再進行分析sql,發現兩者索引都有可能會使用到,但是最後還是選擇了最優的複合索引。

三、查看索引使用情況

show status like 'Handler_read%';	

show global status like 'Handler_read%';	

在這裏插入圖片描述

Handler_read_first:索引中第一條被讀的次數。如果較高,表示服務器正執行大量全索引掃描(這個值越低越好)。

Handler_read_key:如果索引正在工作,這個值代表一個行被索引值讀的次數,如果值越低,表示索引得到的性能改善不高,因爲索引不經常使用(這個值越高越好)。

Handler_read_next :按照鍵順序讀下一行的請求數。如果你用範圍約束或如果執行索引掃描來查詢索引列,該值增加。

Handler_read_prev:按照鍵順序讀前一行的請求數。該讀方法主要用於優化ORDER BY ... DESC。

Handler_read_rnd :根據固定位置讀一行的請求數。如果你正執行大量查詢並需要對結果進行排序該值較高。你可能使用了大量需要MySQL掃描整個表的查詢或你的連接沒有正確使用鍵。這個值較高,意味着運行效率低,應該建立索引來補救。

Handler_read_rnd_next:在數據文件中讀下一行的請求數。如果你正進行大量的表掃描,該值較高。通常說明你的表索引不正確或寫入的查詢沒有利用索引。

四、總結

這些都是基本的索引相關的學習,索引的使用還是需要根據業務需要來進行設計,並不是所有查詢都加上索引都是提升性能的。
謝謝大家閱讀!!互相學習!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章