第六十四篇 索引

1、什麼是索引

1.在關係型數據庫中,索引是一種單獨的、物理層面的對數據表中一列或多列的值進行排序的一種存儲結構,也稱之爲keysql

2.能夠理解:搜索引導,索引是一個特殊的數據結構,其存儲的是數據的關鍵信息與詳細信息的位置關係,例如:圖書的目錄,能夠根據目錄中的頁碼快速找到所需的內容數據庫

3.有三種索引:unique key、primary key、index key數據結構

2、爲何須要索引

加速查詢,當數據量很是大的時候,查詢某一個數據集是很是慢,索引是提高查詢效率最有效的手段測試

3、索引的影響:

1.注意:在數據庫中插入數據會引起索引的重建優化

2.不是說有了索引就能加速,得看你的查詢語句有沒有正確使用索引操作系統

3.索引也須要佔用額外的數據空間設計

4.添加索引後將致使增減刪除修改變慢(寫入)code

4、什麼樣的數據應該添加索引:

1.查詢操做較多,寫入較少而且數據量很大時視頻

2.查詢與寫入操做的佔比爲 10:1 ,或者查詢更多時

5、索引的實現原理

1.相關知識

1.數據庫的索引,實現思路與字典是一致的,須要一個獨立的存儲結構,專門存儲索引數據

2.本質上索引是經過不斷縮小查詢範圍來提升查詢效率

2.磁盤io

1.平均查找一個數據須要花費至少9.15ms,這段時間CPU就會切換到其餘的程序

2.操做系統預讀取:當一次io時,不光把當前磁盤地址的數據讀取,而是把相鄰的數據也都讀取到內存緩衝區中,這個理論對於索引的數據結構設計很是有幫助

3.咱們要加速查詢,必須減小io操做的次數

3.索引數據結構

1.b+樹(第一層爲根節點只能有一個,中間層爲分支節點,最下面的是葉子節點,當葉子節點過多時,分支節點勢必也會相應的增長,上面的根節點也就須要多個,因爲根節點有且只有一個的特性,所以只能增長層數,那麼查詢時遇到的io操做也就相應的增長了,影響效率):

2.在b+樹種,葉子節點纔是存儲真實數據的,葉子數量越多,樹的層級越高,進而致使io操做增長(一層一個io操做)

3.要避免這個問題,在葉子節點中儘量的存儲更多的數據,應該將數據量小的字段做爲索引

4.最左匹配原則:

1.當b+樹的數據項是複合的數據結構,好比(name,age,sex)的時候(多字段聯合索引),b+樹會按照從左到右的順序來創建搜索樹,好比當(張三,20,F)這樣的數據來檢索的時候,b+樹會優先比較name來肯定下一步的所搜方向,若是name相同再依次比較age和sex,最後獲得檢索的數據;但當(20,F)這樣的沒有name的數據來的時候,b+樹就不知道下一步該查哪一個節點,由於創建搜索樹的時候name就是第一個比較因子,必需要先根據name來搜索才能知道下一步去哪裏查詢。好比當(張三,F)這樣的數據來檢索時,b+樹能夠用name來指定搜索方向,但下一個字段age的缺失,因此只能把名字等於張三的數據都找到,而後再匹配性別是F的數據了, 這個是很是重要的性質,即索引的最左匹配特性

2.索引在查找時,是按照從左往右依次比較,若是查詢語句沒有出現最左邊的索引,將沒法加速查詢

5.彙集索引:

1.彙集索引種包含了全部字段的值,若是已指定了主鍵,主鍵就是彙集索引,若是沒有則找一個非空且惟一的字段做爲彙集索引,若是連這個也找不到,則自動生成一個字段做爲彙集索引

2.彙集索引中存儲了全部的數據

6.輔助索引

1.除了彙集索引之外的都叫作輔助索引,包括foreign keyunique

2.輔助索引中只包含當前的索引字段和主鍵的值

7.覆蓋查詢

1.指的是在當前索引結構中就能找到全部須要的數據,若是使用的是彙集索引來查詢那麼必定覆蓋查詢,速度是最快的

2.若是覆蓋索引指定的數據僅在輔助索引中能找到,則不須要再查找彙集索引數據就能找到:

# 好比
# 假設stu表的name字段是一個輔助索引
select name from stu where name = 'jack':

8.回表查詢

1.指的是在當前索引結構中(輔助索引)找不到所需的數據,須要經過主鍵id去彙集索引中查詢,速度慢於彙集索引

2.步驟:從輔助索引中獲取主鍵的值,再拿着主鍵值到彙集索引中找到sex值

# 好比
# name字段是一個輔助索引,而sex字段不是索引
select sex from stu where name = 'jack';

9.查詢速度對比

彙集索引 > 覆蓋索引 > 非覆蓋索引

6、正確使用索引

1.測試

# 建表
create table usr(id int,name char(10),gender char(3),email char(30));
#準備數據
delimiter //
create procedure addData(in num int)
begin 
declare i int default 0;
while  i < num do
    insert into usr values(i,"jack","m",concat("xxxx",i,"@qq.com"));    
set i  = i + 1;
end while;
end//
delimiter ;

#執行查詢語句 觀察查詢時間
select count(*) from usr where id = 1;
#1 row in set (3.85 sec)
#時間在秒級別 比較慢


1.
#添加主鍵
alter table usr add primary key(id);
#再次查詢
select count(*) from usr where id = 1;
#1 row in set (0.00 sec)
#基本在毫秒級就能完成 提高很是大

2.
#當條件爲範圍查詢時
select count(*) from usr where id > 1;
#速度依然很慢 對於這種查詢沒有辦法能夠優化由於須要的數據就是那麼多
#縮小查詢範圍 速度立馬就快了
select count(*) from usr where id > 1 and id < 10;


#當查詢語句中匹配字段沒有索引時 效率測試
select count(*) from usr where name = "jack";
#1 row in set (2.85 sec)
# 速度慢


3.
# 爲name字段添加索引
create index name_index on usr(name);
# 再次查詢
select count(*) from usr where name = "jack";
#1 row in set (3.89 sec)
# 速度反而下降了 爲何?
#因爲name字段的區分度很是低 徹底沒法區分 ,由於值都相同 這樣一來B+樹會沒有任何的子節點,像一根竹竿每一都匹配至關於,有幾條記錄就有幾回io ,全部要注意 區分度低的字段不該該創建索引,不能加速查詢反而下降寫入效率,
#同理 性別字段也不該該創建索引,email字段更加適合創建索引

# 修改查詢語句爲
select count(*) from usr where name = "aaaaaaaaa";
#1 row in set (0.00 sec) 速度很是快由於在 樹根位置就已經判斷出樹中沒有這個數據 所有跳過了

# 模糊匹配時
select count(*) from usr where name like "xxx"; #快
select count(*) from usr where name like "xxx%"; #快
select count(*) from usr where name like "%xxx"; #慢
#因爲索引是比較大小 會從左邊開始匹配 很明顯全部字符都能匹配% 因此全都匹配了一遍


4.索引字段不能參加運算
select count(*) from usr where id * 12 = 120;
#速度很是慢緣由在於 mysql須要取出全部列的id 進行運算以後才能判斷是否成立
#解決方案
select count(*) from usr where id = 120/12;
#速度提高了 由於在讀取數據時 條件就必定固定了 至關於
select count(*) from usr where id = 10;
#速度天然快了

5.有多個匹配條件時 索引的執行順序  and 和 or
#先看and
#先刪除全部的索引
alter table usr  drop primary key;
drop index name_index on usr;

#測試
select count(*) from usr where name = "jack" and gender = "m" and id = 1 and email = "xxxx2@qq.com";
#1 row in set (1.34 sec) 時間在秒級 

#爲name字段添加索引
create index name_index on usr(name);
#測試
select count(*) from usr where name = "jack" and gender = "m" and id = 1 and email = "xxxx2@qq.com";
#1 row in set (17.82 sec) 反而時間更長了

#爲gender字段添加索引
create index gender_index on usr(gender);
#測試
select count(*) from usr where name = "jack" and gender = "m" and id = 1 and email = "xxxx2@qq.com";
#1 row in set (16.83 sec) gender字段任然不具有區分度 

#爲id加上索引
alter table usr add primary key(id);
#測試
select count(*) from usr where name = "jack" and gender = "m" and id = 1 and email = "xxxx1@qq.com";
#1 row in set (0.00 sec) id字段區分度高 速度提高
#雖然三個字段都有索引 mysql並非從左往右傻傻的去查 而是找出一個區分度高的字段優先匹配

#改成範圍匹配
select count(*) from usr where name = "jack" and gender = "m" and id > 1 and email = "xxxx1@qq.com";
#速度變慢了

#刪除id索引 爲email創建索引
alter table usr drop primary key;
create index email_index on usr(email);
#測試
select count(*) from usr where name = "jack" and gender = "m" and id = 1 and email = "xxxx2@qq.com";
#1 row in set (0.00 sec) 速度很是快

#對於or條件 都是從左往右匹配 
select count(*) from usr where name = "jackxxxx" or email = "xxxx0@qq.com";

#注意 必須or兩邊都有索引纔會使用索引 

and 語句中只要有一個存在索引就能提升速度  


6.多字段聯合索引
爲何須要聯合索引
案例:
select count(*) from usr where name = "jack" and gender = "m" and id  > 3 and email = "xxxx2@qq.com";
假設全部字段都是區分度很是高的字段,那麼除了id爲誰添加索引都可以提高速度,可是若是sql語句中沒有出現索引字段,那就沒法加速查詢,最簡單的辦法是爲每一個字段都加上索引,可是索引也是一種數據,會佔用內存空間,而且下降寫入效率
此處就可使用聯合索引,

聯合索引最重要的是順序 按照最左匹配原則 應該將區分度高的放在左邊 區分度低的放到右邊
#刪除其餘索引
drop index name_index on usr;
drop index email_index on usr;
#聯合索引
create index mul_index on usr(email,name,gender,id);
create index mul_index on usr(id,email,gender,name);  # 推薦
# 查詢測試
select count(*) from usr where name = "xx" and id = 1 and email = "xx";
只要語句中出現了最左側的索引(email) 不管在前在後都能提高效率 

drop index mul_index on usr;

2.結論:

1.使用佔用空間最小的字段做爲索引

2.不要在一行中存儲太多的數據,例如小說、視頻,若是字段太多能夠分表

3.儘可能使用覆蓋查詢

4.若是字段區分度低(字段重複度高),創建索引是沒有意義的,反過來講應該將區分度高的字段(好比自增的id)做爲索引

5.模糊匹配中,百分號儘可能不要寫在前面

**6.不要在等號的左邊作運算,例如:select count(*) from usr where id*3 = 6 -- 也會遍歷全部記錄 ;**

7.and語句中會自動找一個具有索引的字段優先執行,因此咱們應該在and語句中至少包含一個具有索引的字段

8.or語句要避免使用,若是要用,則要保證全部字段都有索引才能加速

9.聯合索引中,順序應該將區分度最高的放到左邊,最低的放到右邊,查詢語句中必須保證最左邊的索引出如今語句中

3.須要注意的是:

1.若是要查詢的數據量很是大時,索引將沒法加速

2.不是添加了索引就能提速,須要考慮索引添加的是否合理,SQL語句是否使用到了索引

7、語法

1.建立索引的語法:

create index 索引的名字 on 表名稱(字段名);

2.刪除索引:

drop index 索引名稱 on 表名;

3.聯合索引:

create index 索引名稱 on 表名(字段名1,字段名2,......)
相關文章
相關標籤/搜索