先看下InnoDB的邏輯存儲結構:node
表空間:能夠看作是InnoDB存儲引擎邏輯結構的最高層,全部的數據都存放在表空間中。默認有個共享表空間ibdata1。若是啓用innodb_file_per_table參數,須要注意每張表的表空間內存放的只是數據、索引和插入緩衝Bitmap頁,其餘類的數據,如回滾信息、插入緩衝索引頁、系統事務信息、二次寫緩衝等仍是存放在原來共享表空間中。數據庫
段:
表空間是由各個段組成,常見的段有數據段、索引段、回滾段等。數據段即爲B+樹葉子節點(Leaf node segment),索引段即爲B+樹非葉子節點(Non-leaf node segment)
區性能
區:是由連續頁組成的空間,在任何狀況下每一個區大小都爲1MB。默認狀況下,存儲引擎頁的大小爲16KB,即一個區中一共有連續64個連續的頁。而爲保證頁的連續性,InnoDB存儲引擎一次從磁盤申請4-5個區。優化
頁:
頁(也能夠稱塊),是InnoDB磁盤管理的最小單位。默認每一個頁大小16KB。1.2x版本後也能夠經過參數innodb_page_size設置爲4k、8k、16k3d
如查一條數據:select * from user where id=5;指針
這裏id是主鍵,咱們經過這棵B+樹來查找,首先會去找到根頁,每張表的根頁位置在表空間文件中是固定的;找到根頁後經過二分查找法,定位到id=5的數據應該在指針P5指向的頁中,那麼進一步去page number=5的頁中查找,一樣經過二分查詢法便可找到id=5的記錄:blog
也能夠經過命令查看InnoDB每頁默認16KB:排序
show variables like 'innodb_page_size';索引
先計算非葉子節點, 假設主鍵ID爲bigint類型,長度爲8字節,而指針大小在InnoDB源碼中設置爲6字節,這樣一共14字節事務
而一個頁中能存放多少這樣的單元,其實就表明有多少指針,即16384/14=1170。
那麼能夠算出一棵高度爲2的B+樹,能存放1170*16=18720條這樣的數據記錄。
根據一樣的原理咱們能夠算出一個高度爲3的B+樹能夠存放:1170117016=21902400條這樣的記錄。
因此在InnoDB中B+樹高度通常爲1-3層,它就能知足千萬級的數據存儲。
以下圖,輔助索引查找後,會再回表到聚簇索引,最後找到數據。
InnoDB有且只有一個聚簇索引,而MyISAM中都是非聚簇索引。
聯合索引的最左前綴匹配原則: 對多個字段同時創建的組合索引(有順序,ABC,ACB是徹底不一樣的兩種聯合索引) 以聯合索引(a,b,c)爲例,創建這樣的索引至關於創建了索引a、ab、abc三個索引。另外組合索引實際仍是一個索引,並不是真的建立了多個索引,只是產生的效果等價於產生多個索引。
使用覆蓋好處:
惟一索引:以惟一列生成的索引,該列不容許有重複值,但容許有空值(NULL)
索引下推:MySQL 5.6引入了索引下推優化,能夠在索引遍歷過程當中,對索引中包含的字段先作判斷,過濾掉不符合條件的記錄,減小回表字數。
B樹無論葉子節點仍是非葉子節點,都會保存數據,這樣致使在非葉子節點中能保存的指針數量變少
指針少的狀況下要保存大量數據,只能增長樹的高度,致使IO操做變多,查詢性能變低;
由於聚簇索引是將索引和數據都存放在葉子節點中,若是全部的索引都用聚簇索引,則每個索引都將保存一份數據,會形成數據的冗餘,在數據量很大的狀況下,這種數據冗餘是很消耗資源的。
查詢優化器。
一條SQL語句的查詢,能夠有不一樣的執行方案,至於最終選擇哪一種方案,須要經過優化器進行選擇,選擇執行成本最低的方案。
優化過程大體以下:
索引的優勢以下:
索引的缺點以下:
原則:
不該該
一、索引不是越多越好。索引太多,維護索引須要時間跟空間
二、 頻繁更新的數據,不宜建索引。
三、數據量小的表不必創建索引。
應該
一、重複率小的列建議生成索引。由於重複數據少,索引樹查詢更有效率,等價基數越大越好。
二、數據具備惟一性,建議生成惟一性索引。在數據庫的層面,保證數據正確性
三、頻繁group by、order by的列建議生成索引。能夠大幅提升分組和排序效率
四、常常用於查詢條件的字段建議生成索引。經過索引查詢,速度更快
索引失效的場景
一、模糊搜索:左模糊或全模糊都會致使索引失效,好比'%a'和'%a%'。可是右模糊是能夠利用索引的,好比'a%'
二、隱式類型轉換:好比select * from t where name = xxx , name是字符串類型,可是沒有加引號,因此是由MySQL隱式轉換的,因此會讓索引失效
三、當語句中帶有or的時候:好比select * from t where name=‘sw’ or age=14
四、不符合聯合索引的最左前綴匹配:(A,B,C)的聯合索引,你只where了C或B或只有B,C
其餘注意事項:
- 索引不會包含有 null 值的列,只要列中包含有 null值都將不會被包含在索引中。
- 使用短索引。短索引不只能夠提升查詢速度並且能夠節省磁盤空間和 I/O 操做
- 索引列排序。查詢只使用一個索引,所以若是 where 子句中已經使用了索引的話,那麼 order by 中的列是不會使用索引的。所以數據庫默認排序能夠符合要求的狀況下不要使用排序操做;儘可能不要包含多個列的排序,若是須要最好給這些列建立複合索引。
- 不要在列上進行運算,這將致使索引失效而進行全表掃描
- 不使用 not in 和 <> 操做,這不屬於支持的範圍查詢條件,不會使用索引。
《MySQL技術內幕》
https://mp.weixin.qq.com/s/6j64s9W6ogs5Y8BbhhkgnA
https://mp.weixin.qq.com/s/KB73550tKpNccW-WKxT7-A
https://mp.weixin.qq.com/s/ovMx9Dv9NCFxSsFM98uYFw