認識索引數據庫
認識索引是什麼東西很是關鍵,一個很是恰當的比喻就是書的目錄頁與書的正文內容之間的關係,爲了方便查找書中的內容,經過對內容創建索引造成目錄。所以,首先你要明白的一點就是,索引它也是一個文件,它是要佔據物理空間的。緩存
好比對於MyISAM存儲引擎來講:服務器
.frm後綴的文件存儲的是表結構。數據結構
.myd後綴的文件存儲的是表數據。架構
.myi後綴的文件存儲的就是索引文件。分佈式
以下圖所示:函數
對於InnoDB存儲引擎來講:源碼分析
.frm性能
.ibd後綴的文件存放索引文件和數據(須要開啓innodb_file_per_table參數)學習
以下圖所示:
所以,當你對一張表創建索引時,索引文件的大小也會改變,當你數據表中的數據由於增刪改變化時,索引文件也會變化的,只不過MySQL會自動維護索引,這個過程不須要你介入,這也是爲何不恰當的索引會影響MySQL性能的緣由。
總結:
1. 索引是按照特定的數據結構把數據表中的數據放在索引文件中,以便於快速查找;
2. 索引存在於磁盤中,會佔據物理空間。
索引的類型
B-Tree 索引
以 B-Tree 爲結構的索引是最多見的索引類型,好比 InnoDB 和 MyISAM 都是以 B-Tree 爲索引結構的索引,事實上是以 B+ Tree 爲索引結構,B-Tree 和 B+Tree 區別在於,B+ Tree 在葉子節點上增長了順序訪問指針,方便葉子節點的範圍遍歷。這裏主要介紹一下 InnoDB 和 MyISAM。
InnoDB
InnoDB 支持聚簇索引,聚簇索引和非聚簇索引嚴格來講不是一種索引,而是一種數據存儲方式,這個名字跟它自己的存儲方式有關係,「聚簇「表示數據行和相鄰的鍵值存儲在一塊兒,簡單的說,就是葉子節點中存儲的實際是真實的數據。InnoDB 經過主鍵彙集數據,因此一個表只能有一個聚簇索引,且必須有主鍵,若是沒有定義主鍵,且不存在非空索引能夠代替,InnoDB 會隱式定義一個主鍵做爲聚簇索引。
聚簇索引的二級索引存儲的不是指向行的物理位置的指針,而是行的主鍵值,因此若是經過二級索引查找行,須要找到二級索引的葉子結點得到對應的主鍵值,而後再去查找對應的行。對於 InnoDB,自適應哈希索引能夠減小這樣的重複工做。
鎖
InnoDB 使用的是行鎖,因此支持事務,而 MyISAM 使用的是表鎖,不支持事務。
適用範圍
B-Tree 索引適用於區間查詢,由於 B-Tree 存儲後的葉子節點自己就是有序的,而且 B+ Tree 結構還增長了葉子節點的連續順序指針,對於區間查詢來講就更加方便了。
哈希索引
哈希索引是基於哈希表實現的,只有精確匹配索引全部列的查詢纔有效。方法是,對全部的索引列計算一個 hash code,hash code 做爲索引,在哈希表中保存指向每一個數據行的指針。
優勢
索引自己只存儲 hash code,因此結構很緊湊,而且查找速度很快
限制
索引中的 hash code 是順序存儲的,可是 hash code 對應的數據並非順序的,因此沒法用於排序
不支持部分索引列匹配查找,由於哈希索引是使用索引列的所有內容來計算 hash code
只支持等值比較,不支持範圍查詢
若是哈希衝突嚴重時,必須遍歷鏈表中全部行指針
哈希衝突嚴重的話,索引維護操做的代價也很高
InnoDB 的自適應哈希索引
首先,請注意,自適應哈希索引對於用戶來講是無感知的,這是一個徹底自動、內部的行爲,用戶沒法控制或者配置,可是能夠關閉。
當 InnoDB 注意到某個索引值被使用的很是頻繁時,它會在內存中基於 B-Tree 索引之上再建立一個哈希索引,這樣 B-Tree 也能夠具備哈希索引的一些優勢,好比快速的哈希查找。
固然若是存儲引擎不支持哈希索引,用戶也能夠自定義哈希索引,這樣性能會比較高,缺陷是須要本身維護哈希值,若是採用這種方法,不要使用 SHA1() 和 MD5() 做爲哈希函數,由於這兩個是強加密函數,設計目標是最大限度消除衝突,生成的 hash code 是一個很是長的字符串,浪費大量的空間,哈希索引中對於索引的衝突要求沒有那麼高。
索引的優勢
使用索引能夠減小服務器須要掃描的數據量
使用索引能夠幫助服務器避免排序和臨時表
使用索引能夠將隨機 I/O 變爲順序 I/O
可是不是全部狀況下,索引都是最好的解決方案,對於很是小的表來講,大部分狀況下簡單的全表掃描更高效,對於中到大型表,索引就比較有效,對於特大型的表來講,分區會更加有效。
常見優化方法
聯合索引最左前綴原則
複合索引遵照「最左前綴」原則,查詢條件中,使用了複合索引前面的字段,索引纔會被使用,若是不是按照索引的最左列開始查找,則沒法使用索引。
好比在(a,b,c)三個字段上創建聯合索引,那麼它可以加快a|(a,b)|(a,b,c)三組查詢的速度,而不能加快b|(b,a)這種查詢順序。
另外,建聯合索引的時候,區分度最高的字段在最左邊。
不要在列上使用函數和進行運算
不要在列上使用函數,這將致使索引失效而進行全表掃描。
例以下面的 SQL 語句:
select * from artile where YEAR(create_time) <= '2018';
即便 date 上創建了索引,也會全表掃描,能夠把計算放到業務層,這樣作不只能夠節省數據庫的 CPU,還能夠起到查詢緩存優化效果。
負向條件查詢不能使用索引
負向條件有:!=、<>、not in、not exists、not like 等。
select * from artile where status != 1 and status != 2;
可使用in進行優化:
select * from artile where status in (0,3)
使用覆蓋索引
所謂覆蓋索引,是指被查詢的列,數據能從索引中取得,而不用經過行定位符再到數據表上獲取,可以極大的提升性能。
能夠定義一個讓索引包含的額外的列,即便這個列對於索引而言是無用的。
避免強制類型轉換
當查詢條件左右兩側類型不匹配的時候會發生強制轉換,強制轉換可能致使索引失效而進行全表掃描。
若是phone字段是varchar類型,則下面的SQL不能命中索引:
select * from user where phone=12345678901;
能夠優化爲:
select * from user where phone='12345678901';
範圍列能夠用到索引
範圍條件有:<、<=、>、>=、between等。
範圍列能夠用到索引,可是範圍列後面的列沒法用到索引,索引最多用於一個範圍列,若是查詢條件中有兩個範圍列則沒法全用到索引。
更新頻繁、數據區分度不高的字段上不宜創建索引
更新會變動B+樹,更新頻繁的字段創建索引會大大下降數據庫性能。
「性別」這種區分度不大的屬性,創建索引沒有意義,不能有效過濾數據,性能與全表掃描相似。
區分度可使用 count(distinct(列名))/count(*) 來計算,在80%以上的時候就能夠創建索引。
索引列不容許爲null
單列索引不存null值,複合索引不存全爲null的值,若是列容許爲 null,可能會獲得不符合預期的結果集。
避免使用or來鏈接條件
應該儘可能避免在 where 子句中使用 or 來鏈接條件,由於這會致使索引失效而進行全表掃描,雖然新版的MySQL可以命中索引,但查詢優化耗費的 CPU比in多。
模糊查詢
前導模糊查詢不能使用索引,非前導查詢能夠。
加Java架構師羣獲取Java工程化、高性能及分佈式、高性能、深刻淺出。高架構。性能調優、Spring,MyBatis,Netty源碼分析和大數據等多個知識點高級進階乾貨的直播免費學習權限 都是大牛帶飛 讓你少走不少的彎路的 羣..號是:855801563 對了 小白勿進 最好是有開發經驗的哦~