目錄mysql
1.在關係型數據庫中,索引是一種單獨的、物理層面的對數據表中一列或多列的值進行排序的一種存儲結構,也稱之爲keysql
2.能夠理解:搜索引導,索引是一個特殊的數據結構,其存儲的是數據的關鍵信息與詳細信息的位置關係,例如:圖書的目錄,能夠根據目錄中的頁碼快速找到所需的內容數據庫
3.有三種索引:unique key、primary key、index key數據結構
加速查詢,當數據量很是大的時候,查詢某一個數據集是很是慢,索引是提高查詢效率最有效的手段測試
1.注意:在數據庫中插入數據會引起索引的重建優化
2.不是說有了索引就能加速,得看你的查詢語句有沒有正確使用索引操作系統
3.索引也須要佔用額外的數據空間設計
4.添加索引後將致使增減刪除修改變慢(寫入)code
1.查詢操做較多,寫入較少而且數據量很大時視頻
2.查詢與寫入操做的佔比爲 10:1 ,或者查詢更多時
1.數據庫的索引,實現思路與字典是一致的,須要一個獨立的存儲結構,專門存儲索引數據
2.本質上索引是經過不斷縮小查詢範圍來提升查詢效率
1.平均查找一個數據須要花費至少9.15ms,這段時間CPU就會切換到其餘的程序
2.操做系統預讀取:當一次io時,不光把當前磁盤地址的數據讀取,而是把相鄰的數據也都讀取到內存緩衝區中,這個理論對於索引的數據結構設計很是有幫助
3.咱們要加速查詢,必須減小io操做的次數
1.b+樹(第一層爲根節點只能有一個,中間層爲分支節點,最下面的是葉子節點,當葉子節點過多時,分支節點勢必也會相應的增長,上面的根節點也就須要多個,因爲根節點有且只有一個的特性,所以只能增長層數,那麼查詢時遇到的io操做也就相應的增長了,影響效率):
2.在b+樹種,葉子節點纔是存儲真實數據的,葉子數量越多,樹的層級越高,進而致使io操做增長(一層一個io操做)
3.要避免這個問題,在葉子節點中儘量的存儲更多的數據,應該將數據量小的字段做爲索引
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.索引在查找時,是按照從左往右依次比較,若是查詢語句沒有出現最左邊的索引,將沒法加速查詢
1.彙集索引種包含了全部字段的值,若是已指定了主鍵,主鍵就是彙集索引,若是沒有則找一個非空且惟一的字段做爲彙集索引,若是連這個也找不到,則自動生成一個字段做爲彙集索引
2.彙集索引中存儲了全部的數據
1.除了彙集索引之外的都叫作輔助索引,包括foreign key
與unique
2.輔助索引中只包含當前的索引字段和主鍵的值
1.指的是在當前索引結構中就能找到全部須要的數據,若是使用的是彙集索引來查詢那麼必定覆蓋查詢,速度是最快的
2.若是覆蓋索引指定的數據僅在輔助索引中能找到,則不須要再查找彙集索引數據就能找到:
# 好比 # 假設stu表的name字段是一個輔助索引 select name from stu where name = 'jack':
1.指的是在當前索引結構中(輔助索引)找不到所需的數據,須要經過主鍵id去彙集索引中查詢,速度慢於彙集索引
2.步驟:從輔助索引中獲取主鍵的值,再拿着主鍵值到彙集索引中找到sex值
# 好比 # name字段是一個輔助索引,而sex字段不是索引 select sex from stu where name = 'jack';
彙集索引 > 覆蓋索引 > 非覆蓋索引
# 建表 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;
1.使用佔用空間最小的字段做爲索引
2.不要在一行中存儲太多的數據,例如小說、視頻,若是字段太多能夠分表
3.儘可能使用覆蓋查詢
4.若是字段區分度低(字段重複度高),創建索引是沒有意義的,反過來講應該將區分度高的字段(好比自增的id)做爲索引
5.模糊匹配中,百分號儘可能不要寫在前面
**6.不要在等號的左邊作運算,例如:select count(*) from usr where id*3 = 6 -- 也會遍歷全部記錄 ;**
7.and語句中會自動找一個具有索引的字段優先執行,因此咱們應該在and語句中至少包含一個具有索引的字段
8.or語句要避免使用,若是要用,則要保證全部字段都有索引才能加速
9.聯合索引中,順序應該將區分度最高的放到左邊,最低的放到右邊,查詢語句中必須保證最左邊的索引出如今語句中
1.若是要查詢的數據量很是大時,索引將沒法加速
2.不是添加了索引就能提速,須要考慮索引添加的是否合理,SQL語句是否使用到了索引
create index 索引的名字 on 表名稱(字段名);
drop index 索引名稱 on 表名;
create index 索引名稱 on 表名(字段名1,字段名2,......)