這幾天抽了個時間將《高性能Mysql》看了一下忽覺索引很是之重要,習之而後總結鞏固知識。本文索引使用的是InnoDB存儲引擎。由於本文並非說用索引的好處,因此並不會書寫QPS之類的測試結果請你們見諒。個人mysql版本是8.0.11。mysql
(一)索引使用優化sql
①獨立的列數據庫
②覆蓋索引函數
③索引匹配性能
(二)索引建立優化學習
①前綴索引和索引選擇性測試
②選擇合適的索引順序優化
③不建立冗餘和重複索引3d
咱們有時候雖然建立了合適的索引可是使用不當依然會使索引失效,因此我將書上的索引使用大體總結了一下。在這以前我先介紹一下EXPLAIN生成結果中字段type和Extra的意義,先說一下type常出現的結果。blog
(1)const 表中最多隻有一行用於主鍵和惟一索引的匹配
(2)all全表掃描
(3)ref使用索引並符合最左匹配
(4)index :❶
a.當查詢是索引覆蓋的,即全部數據都可從索引樹獲取的時候(Extra中有Using Index);
b.以索引順序從索引中查找數據行的全表掃描(無 Using Index);
c.若是Extra中Using Index與Using Where同時出現的話,則是利用索引查找鍵值的意思;
d.如單獨出現,則是用讀索引來代替讀行,但不用於查找
接下來咱們解釋一下Extra出現的結果:
(1)using index 使用覆蓋索引。
(2)using where 條件語句中部分條件使用的是索引,其餘條件須要去表中篩選。
(3)using inex condition 條件語句中全部條件都在索引中,可是所須要的數據不在索引中。
(4)using where;using index 條件和所需數據都在索引中。
獨立的列一眼上看去覺得是針對於一個單獨的列建立索引可是實際上並非這樣的。「獨立的列」是指索引列不能是表達式的一部分,也不能是函數的參數❷。這句話的前面一句話在書上是:若是使用獨立的列則mysql不會使用索引。這句話有點模棱兩可,「不會使用索引」究竟是包括索引全掃描仍是不包括索引全掃描,若是包括的話則與實驗結果不相符,若是不包括的話那就沒問題了。廢話很少說仍是用結果來證實吧。首先個人數據庫表結構是這樣子的,以下圖所示:
我建立了兩個單獨列的索引用來測試表達式和函數以下圖所示:
測試sql: explain select age from user where age =2;
從測試結果中咱們能夠看到type爲ref(使用BTree索引),Extra爲Using index(使用了覆蓋索引)
若是咱們把sql語句改成: explain select age from user where age+1=2;解釋結果以下所示:
能夠看到這條查詢語句是使用了索引的,不過是掃描索引的所有數據。接下來測試一下若是條件語句中使用了函數是否會使用索引個人sql語是:EXPLAIN SELECT id from user where TO_DAYS(birthday) >= 50000000;測試結果以下圖所示:
OK,結果也是index。至於書上那句話是對是錯我就不得而知了,不過你們能夠本身去測試一下。
若是把使用索引比做你開了一輛五菱宏光的話,那麼你使用覆蓋索引就是開了一輛蘭博基尼(蘭博基尼的性能是由你本身來決定的)。覆蓋索引簡單的來說就是你所要查詢的字段和條件語句都在一條索引中。接下來又是證實的過程,我建立一個新的索引以下圖所示:
而後我使用這條sql語句 EXPLAIN SELECT first_name,age from user where first_name='張' and age >0,在這條sql語句中我查詢兩個不一樣索引中的列查詢結果以下所示;
在這條sql語句中我使用了兩個索引idx_fk_name和idx_fk_age,查詢的列和查詢條件都是在這兩個索引中,測試的結果爲using where(須要回表查詢所須要的數據)。接下來咱們使用這個sql語句 EXPLAIN SELECT last_name FROM user where first_name = '張',使用結果以下圖所示:
若是咱們書寫的sql語句符合索引匹配原則,那麼咱們就能夠不進行索引的所有數據掃描,結果就是咱們的查詢效率又變高了。那麼索引匹配原則是啥?我就簡略的總結一下吧。
全值匹配就是查詢條件和索引中的全部列進行匹配。如我上面建立的idx_fx_name索引。select * from user where first_name='張' 和 last_name = '三' 這條sql語句就是全值匹配。注意若是寫成last_name='三' and first_name='張'也是全值匹配
我把書中匹配最左前綴和匹配列前綴都劃分爲最左匹配,由於我以爲它都是從最左邊開始匹配的,好像網上也是這麼說的。
最左前綴就是你寫的條件查詢語句針對於某個索引來講它符合從左邊一個一個進行匹配的方式(通過實測條件語句的順序不影響最左匹配的原則),再拿個人idx_fx_name索引來舉個例子。如select * from user where last_name = '三'和 select * from user where first_name = '張' 這兩個sql語句查詢索引的方式都不同,前者是掃描索引全部數據,第二個就只掃描了索引的部分數據。測試結果以下所示:
在符合最左匹配的基礎上可使用範圍進行查詢。
在符合最左匹配的基礎上最後一個查詢條件能夠記性範圍查詢。
咱們先說說索引的選擇性吧。索引的選擇性是指不重複的索引值(也稱爲基數,cardinality)和數據表的記錄總數(#T)的比值,範圍從1/#T到1之間❸。這句話通俗的理解就是你選擇做爲索引(固然是隻能選擇某個字段,字段的所有或者部分)的數據在表中這個字段列中重複率越低越好,由於這樣能夠過濾更多的數據行。前綴索引就是能夠拿某個字段的前綴做爲索引之因此把前綴因此和索引選擇性放到一塊兒說是爲了解決當咱們選擇一個特別長的字段做爲索引時首先會很浪費空間其次是查詢的時候速度確定會比較慢。
那麼咱們怎麼計算索引選擇性的高低呢?這個有方法的,方法就是經過關鍵字DISTINCT 和 Count來計算索引的選擇性。如我計算first_name的選擇性高低能夠這樣計算:
select count(DISTINCT first_name) / count(1) as a1 from user;
若是我要計算以first_name前三個字符做爲索引的話計算選擇性能夠這樣寫:
select count(DISTINCT LEFT(first_name,3)) / count(1) as a1 from user;
經過不斷的修改所包含的前綴的大小咱們就能找到選擇性高的索引。
其實選擇合適的索引序列我以爲根據實際狀況來作分析。不過通常來講咱們都把選擇性高的放在前面,其餘的就是要根據where子句中的排序、分組和範圍條件等其餘因素來選擇索引的序列
這裏有兩個問題擺在咱們的面前什麼是冗餘的索引?什麼是重複索引?
重複索引:具備相同列的索引就是重複索引。如(A,B)和(B,A)就是重複索引。
冗餘索引:一個索引的子集就是冗餘索引。如(A,B,C) 和(A,B) (B,C)就是冗餘索引。
從通常狀況來講就是儘可能不建立重複索引和冗餘索引,可是在特殊的狀況下咱們能夠建立冗餘索引。
以上就是我學習《高性能mysql》書籍的總結。若是有什麼問題請你們及時反饋給我畢竟互相交流才能促進學習。
❶http://blog.51cto.com/lijianjun/1881208
❷《高性能mysql》第五章第三節
❸《高性能msql》第五章第三節第二小節