御麗詩妃談MySQL索引怎麼用

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

追逐仰望星空 2020-08-05 10:43:38

推薦學習

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

爲了能讓索引能有更直觀的效率,我在一張表裏扔進了百萬條數據(光靠這些數據,生成數據代碼寫了一個小時,解決MySQL8的文件導入權限問題解決了兩個小時,導入數據花費了一個小時,我太難了~(;д;)。可是,一切不以實踐數據爲標準的理論都是**耍!流!氓!**o(´^`)o)。讓咱們一邊講解MySQL的使用一邊看一下索引能爲咱們的查詢帶來的性能提高吧。mysql

索引使用的優點

提升查詢效率,簡單來講就是查的再快更快!外面說的什麼提升表的速度、加速錶鏈接、減小分組及排序時間、提升系統性能,說白了都是快,查得快!(順便我發現百度出來的索引使用優點劣勢貌似就那麼一兩套,真就天下文章一大抄唄,抄個人也歡迎,煩請註明出處或者做者Solid_lele哈)程序員

具體會有多快呢?sql

這是沒有索引的百萬級數據查找(這個算快的了,慢的四十秒,時間不是很穩定,由於是從磁盤塊中讀取數據,原理參照我開頭提到的那篇文章)10.797s:數據庫

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

這是有索引的百萬級數據查找0.272s:緩存

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

差了四十多倍,就至關於別人一年賺四十多萬,我一年賺一萬,這差距真的是太痛苦了。ide

索引使用的劣勢

凡事具備兩面性,有好就會有壞,拿時間換空間或者拿空間換時間這種操做家常便飯,索引就是拿空間換時間,雖然並非那麼典型(由於它核心並非增大空間減小時間,而是經過維護相似目錄的結構減小IO的讀寫次數,最典型的空間換時間是計數排序)。壞處天然就出現了:函數

一、維護成本高

索引維護了一個相似於目錄的結構,你能夠聯想新華字典的目錄,當你建立目錄的時候,若是沒有程序幫忙,你本身手寫目錄的話,須要一頁一頁的去翻去看肯定那個字在哪兒,而後寫進目錄裏;萬一有個字被刪了或者加了一個字還要從新調整一遍目錄。對程序也是同樣,索引的建立和維護是須要消耗性能的,因此會下降數據庫修改時的性能。就以建立索引來講,建立百萬級別的varchar數據BTREE索引,數據內容長度爲20個漢字,消耗的時間爲61.234s:oop

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

再比較一下維護索引的代價,好比無索引百萬級別數據插入一條時間爲0.480s:性能

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

而有索引的百萬級別數據插入一條時間爲1.273s:學習

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

差距其實還挺大的(請忽略我亂打插入的三個字)。

二、所佔空間大

既然提到空間換時間,那麼空間的浪費是不可避免的,我作了下面的這個測試(測試數據庫MySQL8,數據庫運行環境Windows)。

首先建立了一個臨時表tmp_name,其中只有一列名爲c_name的字段,發現文件夾中存儲的ibd文件初始大小爲112k,插入百萬條數據(100萬條數據整哦,一個很少一個很多哦)後,大小爲40960k:

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

而後建立了一個BTREE索引,大小變爲了73728k:

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

大約多用了一倍的空間。但實際中不可能每一個字段都加索引,生產中爲索引預留的空間大概佔數據大小的五分之一就夠了。在這個數據爲重效率至上的時代,磁盤的空間成本貌似仍是比較划算的。

其實使用索引還有個劣勢,就是你須要花費時間來看我這篇文章o(////▽////)q

索引的分類

單值索引:就是一個索引只包含單個列,一個表能夠有多個單列索引;惟一索引:就是索引列的值必須惟一,但容許有空值(主鍵索引就是惟一索引,但它不能爲null);複合索引:就是聯合索引,也就是一個索引包含多個列;

我看網上介紹索引的都說了惟一索引和複合索引,咋,單值索引就不算索引了?互相「借鑑」的時候好歹也本身思考一下好不啦。

索引的建立規則

索引既然有這麼明顯的優點以及劣勢,咱們天然要把它的優點最大化,劣勢儘量避免。因此索引最好能作到:

一、常常做爲查詢或者排序條件;

二、重複值儘量少;

三、增刪改不會太多。

知足上面三條規則的就能夠建立索引了(不符合規則怎麼樣這種數據我實在是不想貼出來了,就直接說吧,這篇文章到如今算上造數據+各類實驗寫了十個小時了,還沒結束,又遇上LOL的無限火力,明明是週末卻只能羨慕別人在玩的我非常痛苦哇)。

因此總結一下適合建立的狀況(就是以上面三個條件做爲參考的各類狀況啦):

一、主鍵:主鍵是自動創建惟一索引的,不用咱操心;二、頻繁做爲查詢條件的字段:畢竟就是爲了查的快才建立索引的嘛;三、查詢中與其它表關聯的字段:這就是外鍵了,不只關聯查詢用到了,重複值不多,很棒;四、若是有多個字段,儘可能建立組合索引:當查詢優化器以爲分析兩個查詢索引太費勁了,還不如用一個的時候,它就給你用一個,因此只要遵循最佳左前綴原則,仍是組合索引更靠譜;五、查詢中排序的字段:排序字段若經過索引去訪問將大大提升排序速度;六、查詢中統計或者分組字段:和上面狀況同樣啦。

那何時不適合建立呢:

一、表記錄太少並且不會變得不少:夭壽啦,就這麼幾百條數據建索引不如直接查一遍;

二、頻繁更新的字段不適合建立索引:維護索引很累的,查的沒這麼多可是總改總改,系統就像被常常需求變更的程序員,不跟你打起來就不錯了;

三、Where條件裏用不到的字段不建立索引:不要問爲何,問就是出門左轉是電梯;

索引的CRD沒有U

建立Create

#該語句添加一個主鍵,這意味着索引值必須是惟一的,且不能爲NULLALTER TABLE [table_name] ADD PRIMARY KEY ([column_list]);
#這條語句建立索引的值必須是惟一的(除了NULL外,NULL可能會出現屢次)。
ALTER TABLE [table_name] ADD UNIQUE [index_name] ([column_list]);
#添加普通索引,索引值可出現屢次。
ALTER TABLE [table_name] ADD INDEX [index_name] ([column_list]);
#該語句指定了索引爲 FULLTEXT ,用於全文索引。
ALTER TABLE [table_name] ADD FULLTEXT [index_name] ([column_list]);

查看Read

SHOW INDEX FROM [table_name];

刪除Drop

DROP INDEX [index_name] ON [table_name];

更新,很差意思沒有,想改就是刪了重加。

索引的分析(Explain)

終於走到這兒了,真刀真槍打一架吧,前面都是開胃小菜,如今纔是正餐,但估計大家都快吃飽了,我也作累了,就很尷尬。

Explain是什麼

話很少說,看官網API說明:

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

The EXPLAIN statement provides information about how MySQL executes statements. EXPLAIN works with SELECT, DELETE, INSERT, REPLACE, and UPDATE statements.

EXPLAIN returns a row of information for each table used in the SELECT statement. It lists the tables in the output in the order that MySQL would read them while processing the statement. MySQL resolves all joins using a nested-loop join method. This means that MySQL reads a row from the first table, and then finds a matching row in the second table, the third table, and so on. When all tables are processed, MySQL outputs the selected columns and backtracks through the table list until a table is found for which there are more matching rows. The next row is read from this table and the process continues with the next table.

EXPLAIN語句提供了關於MySQL怎樣執行語句的信息。EXPLAIN能夠用來分析SELECT、DELETE、INSERT、REPLACE和UPDATE語句。EXPLAIN爲SELECT語句中使用的每一個表返回一行信息。它按照MySQL在處理語句時讀取的順序,列出執行輸出中的表。MySQL使用嵌套循環鏈接方法解析全部鏈接。這意味着MySQL從第一個表中讀取一行,而後在第二個表、第三個表中找到匹配的行,以此類推。當處理完全部表後,MySQL將輸出所選的列,並經過表列表進行回溯,直到找到一個具備更多匹配行的表爲止。從該表讀取下一行,而後繼續處理下一個表。

說白了就是能讓你看錶的讀取順序、用索引狀況、表之間的引用、優化器查詢的狀況這些信息的執行狀況分析。(不容許說每一個漢字都認識湊到一塊兒不知道啥意思了)

Explain的使用及分析

使用:就是Explain+你的sql語句:

EXPLAIN SELECT * FROM t_solid_test where c_name = 'Solid';

查詢出來長這個樣子:

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

這麼多信息都表明什麼?咱一個個來看。

id

select查詢的序列號,包含一組數字,表示查詢中執行select子句或操做表的順序。

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

id值越大,優先級越高,越先執行;id若是相同,從上往下順序執行。

select_type

查詢類型

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

SIMPLE:簡單的 select 查詢,查詢中不包含子查詢或者UNION;

PRIMARY:查詢中若包含任何複雜的子部分,最外層查詢則被標記爲;

UNION:若第二個SELECT出如今UNION以後,則被標記爲UNION; 若UNION包含在FROM子句的子查詢中,外層SELECT將被標記爲:DERIVED;

DEPENDENT UNION:一個UNION中的第二個或更高版本的SELECT語句 ,取決於外部查詢;

UNION RESULT:UNION的結果。

SUBQUERY:在SELECT或WHERE列表中包含了子查詢;

DEPENDENT SUBQUERY:在子查詢中的第一個SELECT,取決於外部查詢

DERIVED:在FROM列表中包含的子查詢被標記爲DERIVED(衍生) MySQL會遞歸執行這些子查詢, 把結果放在臨時表裏;

DEPENDENT DERIVED:派生表依賴於另外一個表;

MATERIALIZED:物化子查詢;

UNCACHEABLE SUBQUERY:子查詢,其結果沒法緩存,必須針對外部查詢的每一行從新進行評估;

UNCACHEABLE UNION:UNION 屬於不可緩存子查詢的中的第二個或更高版本的選擇(請參閱UNCACHEABLE SUBQUERY的參考資料 );

partitions

查詢分區的匹配記錄。若是未分區則爲NULL;

table

顯示這一行的數據是關於哪張表的;

type

訪問類型排列, 顯示查詢使用了何種類型:

system:表只有一行記錄(等於系統表),這是const類型的特列,平時不會出現,這個也能夠忽略不計。

const:表示經過索引一次就找到了,const用於比較primary key或者unique索引。由於只匹配一行數據,因此很快 如將主鍵置於where列表中,MySQL就能將該查詢轉換爲一個常量。

eq_ref:惟一性索引掃描,對於每一個索引鍵,表中只有一條記錄與之匹配。常見於主鍵或惟一索引掃描。

ref:非惟一性索引掃描,返回匹配某個單獨值的全部行. 本質上也是一種索引訪問,它返回全部匹配某個單獨值的行,然而, 它可能會找到多個符合條件的行,因此他應該屬於查找和掃描的混合體。

fulltext:使用FULLTEXT 索引執行聯接。

ref_or_null:這種鏈接類型相似於 ref,可是除了MySQL會額外搜索包含NULL值的行。

index_merge:此聯接類型指示使用索引合併優化。在這種狀況下,key輸出行中的列包含所用索引的列表,並key_len包含所用索引 的最長鍵部分的列表。有關更多信息,請參見 第8.2.1.3節「索引合併優化」。

unique_subquery:此類型替換 如下形式的eq_ref某些 IN子查詢:value IN (SELECT primary_key FROM single_table WHERE some_expr),unique_subquery 只是一個索引查找函數,它徹底替代了子查詢以提升效率。

index_subquery:此鏈接類型相似於 unique_subquery。它代替IN子查詢,但適用於如下形式的子查詢中的非惟一索引:value IN (SELECT key_column FROM single_table WHERE some_expr)。

range:只檢索給定範圍的行,使用一個索引來選擇行。key 列顯示使用了哪一個索引 通常就是在你的where語句中出現了between、<、>、in等的查詢 這種範圍掃描索引掃描比全表掃描要好,由於它只須要開始於索引的某一點,而結束於另外一點,不用掃描所有索引。

index:Full Index Scan,index與ALL區別爲index類型只遍歷索引樹。這一般比ALL快,由於索引文件一般比數據文件小(也就是說雖然all和Index都是讀全表,但index是從索引中讀取的,而all是從硬盤中讀的)。

all:Full Table Scan,將遍歷全表以找到匹配的行。備註:通常來講,得保證查詢至少達到range級別,最好能達到ref。

possible_keys

顯示可能應用在這張表中的索引,一個或多個。 查詢涉及到的字段上若存在索引,則該索引將被列出,但不必定被查詢實際使用。

key

實際使用的索引。若是爲NULL,則沒有使用索引。查詢中若使用了覆蓋索引,則該索引和查詢的select字段重疊。

key_len

表示索引中使用的字節數,可經過該列計算查詢中使用的索引的長度。在不損失精確性的狀況下,長度越短越好。key_len顯示的值爲索引字段的最大可能長度,並不是實際使用長度,即key_len是根據表定義計算而得,不是經過表內檢索出的。

ref

顯示索引的哪一列被使用了,若是可能的話,是一個常數。哪些列或常量被用於查找索引列上的值。

rows

根據表統計信息及索引選用狀況,大體估算出找到所需的記錄所須要讀取的行數。

Extra

包含不適合在其餘列中顯示但十分重要的額外信息:

Using filesort:說明mysql會對數據使用一個外部的索引排序,而不是按照表內的索引順序進行讀取。MySQL中沒法利用索引完成的排序操做稱爲「文件排序」。

Using temporary:使用了臨時表保存中間結果,MySQL在對查詢結果排序時使用臨時表。常見於排序order by 和分組查詢 group by。

USING index:表示相應的select操做中使用了覆蓋索引(Covering Index),避免訪問了表的數據行,效率不錯! 若是同時出現using where,代表索引被用來執行索引鍵值的查找; 若是沒有同時出現using where,代表索引用來讀取數據而非執行查找動做。

Using where:代表使用了where過濾。

using join buffer:使用了鏈接緩存。

impossible where:where子句的值老是false,不能用來獲取任何元素。

select tables optimized away:在沒有GROUPBY子句的狀況下,基於索引優化MIN/MAX操做或者對於MyISAM存儲引擎優化COUNT(*)操做,沒必要等到執行階段再進行計算, 查詢執行計劃生成的階段即完成優化。

distinct:優化distinct操做,在找到第一匹配的元組後即中止找一樣值的動做

索引使用案例

最理想的狀況

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

最佳左前綴原則

後臺建立的索引是name_sex_age的聯合索引,聯合索引中,從左往右匹配,若是最開始匹配不到,則索引失效。

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

儘可能不用函數操做索引

在索引列上作任何操做(計算、函數、(自動or手動)類型轉換),會致使索引失效而轉向全表掃描。

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

索引中範圍條件右邊的列不會被使用

下面這個聯合索引,當聯合索引中間的值查詢條件爲範圍查詢時,右側的索引不會被用到。

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

少用select *

儘可能使用覆蓋索引(只訪問索引的查詢(索引列和查詢列一致)),減小select *。

MySQL索引怎麼用?究竟能有多快?看完這篇你就懂了

 

索引失效的幾個狀況

不等於(!= 或者<>)、is null、is not null 、or、like以通配符開頭(’%abc…’)、字符串不加單引號(類型轉換)

這就不貼圖了,沒啥可貼的,用了type就是ALL;

索引使用的總結建議

最後,給一個索引使用的總結吧:

對於單鍵索引,儘可能選擇針對當前query過濾性更好的索引。在選擇組合索引的時候,當前Query中過濾性最好的字段在索引字段順序中,位置越靠前越好。在選擇組合索引的時候,儘可能選擇能夠可以包含當前query中的where字句中更多字段的索引。儘量經過分析統計信息和調整query的寫法來達到選擇合適索引的目的。

相關文章
相關標籤/搜索