什麼是索引?
索引在MySQL中也叫是一種「鍵」,是存儲引擎用於快速找到記錄的一種數據結構。索引對於良好的性能
很是關鍵,尤爲是當表中的數據量愈來愈大時,索引對於性能的影響愈發重要。
索引優化應該是對查詢性能優化最有效的手段了。索引可以輕易將查詢性能提升好幾個數量級。
索引至關於字典的音序表,若是要查某個字,若是不使用音序表,則須要從幾百頁中逐頁去查。html
索引的原理
索引原理
索引的目的在於提升查詢效率,與咱們查閱圖書所用的目錄是一個道理:先定位到章,而後定位到該章下的一個小節,而後找到頁數。類似的例子還有:查字典,查火車車次,飛機航班等mysql
本質都是:經過不斷地縮小想要獲取數據的範圍來篩選出最終想要的結果,同時把隨機的事件變成順序的事件,也就是說,有了這種索引機制,咱們能夠老是用同一種查找方式來鎖定數據。算法
數據庫也是同樣,但顯然要複雜的多,由於不只面臨着等值查詢,還有範圍查詢(>、<、between、in)、模糊查詢(like)、並集查詢(or)等等。數據庫應該選擇怎麼樣的方式來應對全部的問題呢?咱們回想字典的例子,能不能把數據分紅段,而後分段查詢呢?最簡單的若是1000條數據,1到100分紅第一段,101到200分紅第二段,201到300分紅第三段......這樣查第250條數據,只要找第三段就能夠了,一會兒去除了90%的無效數據。但若是是1千萬的記錄呢,分紅幾段比較好?稍有算法基礎的同窗會想到搜索樹,其平均複雜度是lgN,具備不錯的查詢性能。但這裏咱們忽略了一個關鍵的問題,複雜度模型是基於每次相同的操做成原本考慮的。而數據庫實現比較複雜,一方面數據是保存在磁盤上的,另一方面爲了提升性能,每次又能夠把部分數據讀入內存來計算,由於咱們知道訪問磁盤的成本大概是訪問內存的十萬倍左右,因此簡單的搜索樹難以知足複雜的應用場景。sql
磁盤IO與預讀
前面提到了訪問磁盤,那麼這裏先簡單介紹一下磁盤IO和預讀,磁盤讀取數據靠的是機械運動,每次讀取數據花費的時間能夠分爲尋道時間、旋轉延遲、傳輸時間三個部分,尋道時間指的是磁臂移動到指定磁道所須要的時間,主流磁盤通常在5ms如下;旋轉延遲就是咱們常常據說的磁盤轉速,好比一個磁盤7200轉,表示每分鐘能轉7200次,也就是說1秒鐘能轉120次,旋轉延遲就是1/120/2 = 4.17ms;傳輸時間指的是從磁盤讀出或將數據寫入磁盤的時間,通常在零點幾毫秒,相對於前兩個時間能夠忽略不計。那麼訪問一次磁盤的時間,即一次磁盤IO的時間約等於5+4.17 = 9ms左右,聽起來還挺不錯的,但要知道一臺500 -MIPS(Million Instructions Per Second)的機器每秒能夠執行5億條指令,由於指令依靠的是電的性質,換句話說執行一次IO的時間能夠執行約450萬條指令,數據庫動輒十萬百萬乃至千萬級數據,每次9毫秒的時間,顯然是個災難。下圖是計算機硬件延遲的對比圖,供你們參考:數據庫
考慮到磁盤IO是很是高昂的操做,計算機操做系統作了一些優化,當一次IO時,不光把當前磁盤地址的數據,而是把相鄰的數據也都讀取到內存緩衝區內,由於局部預讀性原理告訴咱們,當計算機訪問一個地址的數據的時候,與其相鄰的數據也會很快被訪問到。每一次IO讀取的數據咱們稱之爲一頁(page)。具體一頁有多大數據跟操做系統有關,通常爲4k或8k,也就是咱們讀取一頁內的數據時候,實際上才發生了一次IO,這個理論對於索引的數據結構設計很是有幫助。性能優化
認識key
認識mysql中的key: index key 普通索引,可以加速查詢,輔助索引 unique key 惟一 + 索引,輔助索引 primary key 惟一 + 非空 + 彙集索引 主鍵做爲條件的查詢若是可以讓索引生效那麼效率老是更高 foreign key 自己沒有索引的,可是它關聯的外表中的字段是unique索引 primary key 和unique 標識的字段不須要再添加索引 直接就能夠利用索引加速查詢 能用unique的時候儘可能不用index unique除了是索引以外還能作惟一約束,若是作了惟一約束 b+樹就更健康
索引 : 實際上就是一個搜索表時使用的目錄 彙集索引 : 葉子節點內直接存儲行內容 只有innodb存儲引擎纔有彙集索引 主鍵 輔助索引 : 葉子節點中的數字指向數據的具體地址 innodb中和myisam中均可以存在 innodb 對應2個文件 表結構 數據 + 索引 myisam 對應3個文件 表結構 純數據 輔助索
彙集索引和輔助索引
id name gender age 1 alex male 18 primary key index 彙集索引 輔助索引 建立普通索引 create index 索引名 on 表名(字段名) desc 表名; +--------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------+-----------------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | YES | | NULL | | | sex | enum('male','female') | NO | | male | | | age | int(11) | YES | MUL | NULL | | | dep_id | int(11) | YES | | NULL | | +--------+-----------------------+------+-----+---------+----------------+ show create table 表名; | employee | CREATE TABLE `employee` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, `sex` enum('male','female') NOT NULL DEFAULT 'male', `age` int(11) DEFAULT NULL, `dep_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `ind_age` (`age`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 |
結論:數據結構
彙集索引:葉子節點直接存儲行內容,健康的樹查詢速度快僅需3次IO;(select * from 表名 where id = 20;),用匯集索引查找內容;post
輔助索引:葉子節點中的數字指向數據的內存地址,咱們經過用輔助索引查找到數據的內存地址後須要回表到彙集索引,拿着數據的內存地址找到真實的數據,須要6次IO;性能
注意:若是咱們在建立表結構的時候沒有建立主鍵(彙集索引),那麼mysql會自動的幫咱們建立一個主鍵,這個主鍵咱們是看不到的,由於只有主鍵纔是彙集索引,那麼咱們之後查詢表中的數據都是經過輔助索引查詢的,由於輔助索引比彙集索引遇到的IO多,查詢速度更慢些,因此通常咱們在建立表結構的時候都是自定義主鍵,這樣能更好的利用匯集索引的優點;大數據