老劉是即將找工作的研究生,自學大數據開發,一路走來,感慨頗深,網上大數據的資料良莠不齊,於是想寫一份詳細的大數據開發指南。這份指南把大數據的【基礎知識】【框架分析】【源碼理解】都用自己的話描述出來,讓伙伴自學從此不求人。 大數據開發指南地址如下:
github:https://github.com/BigDataLaoLiu/BigDataGuide 碼雲:https://gitee.com/BigDataLiu/BigDataGuide 您的點贊是我持續更新的動力,禁止白嫖,看了就要有收獲,有需要聯系公眾號:努力的老劉。
今天給大家分享的是大數據開發基礎部分MySQL的索引篇,這篇內容大家一定要跟着練習,不然等於白看!
索引是什么?
在日常開發中常常會遇到查詢比較慢的情況,我們的第一反應就是給它加索引,那索引是什么呢?官方介紹索引是幫助MySQL高效獲取數據的數據結構,數據庫索引好比是一本書的目錄,能加快數據庫的數據查詢速度。
那索引的好處有哪些呢?
-
它可以提高數據檢索的效率,降低數據庫的成本。 -
通過索引對數據進行排序,降低數據排序的成本,降低CPU消耗。
任何事情都會有正反面,索引也不例外,那索引的壞處有哪些呢?
-
索引會占據磁盤空間。 -
索引雖然會提高查詢效率,但會降低更新表的效率。 -
MySQL不僅要保存數據,還有保存或者更新對應的索引文件。
那是不是有壞處就不用索引呢?
當然不是,索引必須拿來。一般來說索引本身也很大,不可能全部存儲在內存中,因此索引往往是存儲在磁盤文件上的文件中。
索引的分類
-
單列索引: -
普通索引:add unique -
唯一索引:索引列中的值必須是唯一的,但允許有空值,add unique index -
主鍵索引:是一種特殊的唯一索引,不允許有空值
-
-
組合索引: -
在表中的多個字段組合上創建的索引 -
組合索引的使用,需要遵循最左前綴原則 -
一般情況下,建議使用組合索引代替單列索引(主鍵索引除外)
-
-
全文索引:只有在MyIsam、InnoDB上才能使用,而且只能在char、varchar、text類型字段上使用全文索引。 -
空間索引:一般用不到
索引的使用
創建索引
CREATE INDEX index_name ON table(column(length)) ;
刪除索引
DROP INDEX index_name ON table;
查看索引
SHOW INDEX FROM table_name \G;
索引原理(重點)
索引的存儲結構
說索引原理之前,先說說索引存儲結構。索引是在存儲引擎中實現的,也就是不同的存儲引擎,會使用不同索引。其中MyIsam和InnoDB只支持B+數索引,老劉先不講B樹和B+樹的概念,大家自行搜索。
接下來就是索引的重點,搞清楚了非聚集索引和聚集索引,索引原理就差不多了!
非聚集索引(MyIsam)
它說的是B+樹葉子節點只會存儲數據行(數據文件)的指針,即數據和索引不在一起。它包含主鍵索引和輔助索引,都會存儲指針的值。
主鍵索引

MyIsam中B+樹葉子節點存儲的數據是數據的指針值,通過索引樹找到對應的索引,然后通過索引中存儲的記錄指針,找到數據文件中對應的記錄。
輔助索引(次要索引)

在MyIsam中,主索引和輔助索引在結構上沒有任何區別,只是主索引要求key是唯一的,而輔助索引的key是可以重復的。
聚集索引(InnoDB)
-
主鍵索引(聚集索引)的葉子節點會存儲數據行,也就是說數據和索引在一起。 -
輔助索引只會存儲主鍵值。 -
如果沒有主鍵,則使用唯一索引建立聚集索引;如果沒有唯一索引,MySQL會按照一定規則創建聚集索引。
主鍵索引
在InnoDB中要求表必須有主鍵(MyIsam可以沒有),如果沒有顯示指定,則MySQL系統會自動選擇一個可以唯一標識數據記錄的列作為主鍵,如果不存在這種列,則MySQL自動為InnoDB表生成一個隱含字段作為主鍵類型為長整形。

上圖是 InnoDB 主索引(同時也是數據文件)的示意圖,可以看到葉節點包含了完整的數據記錄,這種索引叫做聚集索引。因為 InnoDB 的數據文件本身要按主鍵聚集。
輔助索引
InnoDB 的輔助索引 data 域存儲相應記錄主鍵的值而不是地址。換句話說,InnoDB 的所有輔助索引都引用主鍵作為 data 域。

聚集索引這種實現方式使得按主鍵的搜索十分高效,但是輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵,然后用主鍵到主索引中檢索獲得記錄,即回表查詢。
select * from user where name='Alice'
根據這段SQL語句,會進行回表查詢,檢索兩次,才會獲得記錄。回表性能比較低,盡量做到不回表。
索引使用場景
介紹完索引的相關概念后,老劉必須給講講哪些場景下可以使用場景,大家記幾個就行。
哪些情況下需要使用索引
-
主鍵自動建立唯一索引 -
頻繁作為查詢條件的字段應該創建索引 -
多表關聯查詢中,關聯字段應該創建索引 -
查詢中排序的字段應該創建索引 -
頻繁查詢字段 -
查詢中統計或者分組字段應該創建索引
哪些情況下不需要創建索引
-
表記錄太少,沒必要創建索引 -
經常進行增刪改的表 -
頻繁更新的字段 -
where條件里使用頻率不高的字段
為什么推薦多使用組合索引?
為了節省mysql索引存儲空間以及提升搜索性能,能使用組合索引就不使用單列索引。
使用組合索引需要遵循最左前綴原則,什么是最左前綴原則?
-
前綴索引:where like a%
通配符%在右邊不在左邊,什么是前綴索引呢?當索引是很長的字符序列時,這個索引會很慢,占用內存。如果以name為索引,當name對應的字符串很長時,就可以用前綴索引where like a%。
-
從左到右都有索引,不能斷,直到遇到范圍查詢<,>,between。
索引失效
我們進行數據查詢很慢時,可能就會存在索引失效的情況。遇到這種情況不要怕,我們可以使用explain命令對select語句的執行計划進行分析。explain出來的信息有10列,分別是
id、select_type、table、type、possible_keys、key、key_len、ref、rows、Extra
下面老劉就使用一個案例進行這些參數進行說明,大家可以跟着老劉一起練習。這10個參數老劉只講重要的,其他的大家自行學習。
--用戶表
create table tuser(
id int primary key,
loginname varchar(100),
name varchar(100),
age int,
sex char(1),
dep int,
address varchar(100)
);
--部門表
create table tdep(
id int primary key,
name varchar(100)
);
--地址表
create table taddr(
id int primary key,
addr varchar(100)
);
--創建普通索引
mysql> alter table tuser add index idx_dep(dep);
--創建唯一索引
mysql> alter table tuser add unique index idx_loginname(loginname);
--創建組合索引
mysql> alter table tuser add index idx_name_age_sex(name,age,sex);
--創建全文索引
mysql> alter table taddr add fulltext ft_addr(addr);
id
每個SELECT語句都會自動分配的一個唯一標識符,表示查詢中操作表的順序,有四種情況:
-
id相同:執行順序由上到下 -
id不同:如果是子查詢,id號會自增,id越大,優先級越高。 -
id相同的不同的同時存在 -
id列為null的就表示這是一個結果集,不需要使用它來進行查詢。
select_type(重要)
表示查詢類型,主要用於區別普通查詢、聯合查詢(union、union all)、子查詢等復雜查詢。
simple,表示不需要union操作或者不包含子查詢的簡單select查詢。

primary,一個需要union操作或者含有子查詢的select,位於最外層的單位查詢的select_type即為primary,並且只有有一個 。

先執行括號里面的sql語句,再執行外面的sql語句,內層的查詢就是subquery。
subquery,除了from字句中包含的子查詢外,其他地方出現的子查詢都可能是subquery。
dependent subquery,表示這個subquery的查詢要受到外部表查詢的影響。

union,它連接的兩個select查詢,第一個查詢是PRIMARY,除了第一個表外,第二個以后的表select_type都是union。

dependent union,它與union一樣,出現在union 或union all語句中,但是這個查詢要受到外部查詢的影響。

union result,它包含union的結果集,在union和union all語句中,因為它不需要參與查詢,所以id字段為null。
derived,from字句中出現的子查詢,也叫做派生表,其他數據庫中可能叫做內聯視圖或嵌套select。

可以理解為就是from字句后面出現子查詢,取個別名,叫派生表。
table
顯示查詢的表名,如果查詢使用了別名,那么這里顯示的是別名。
type(重要)
它會顯示很多參數類型,性能依次從好到壞顯示為這樣:
system,const,eq_ref,ref,fulltext,ref_or_null,unique_subquery,index_subquery,range,index_merge,index,ALL
除了all之外,其他的type都可以使用到索引,除了index_merge之外,其他的type只可以用到一個索引,優化器會選用最優索引一個,最少要索引使用到range級別。 老劉只講這個重要的,有些內容也沒搞清楚。
system
可遇不可求,表中只有一行數據或是空表。
const(重要)
使用唯一索引或主鍵,返回記錄一定是1行記錄的等值where條件。

eq_ref(重要)
一般是連接字段主鍵或者唯一性索引。
此類型通常出現在多表的 join 查詢,表示對於前表的每一個結果,都只能匹配到后表的一行結果。並且查詢的比較操作通常是 '=',查詢效率較高。

ref(重要)
針對非唯一性索引,使用等值(=)查詢非主鍵。或者是使用了最左前綴規則索引的查詢。

range(重要)
索引范圍掃描,常見於使用>,<,is null,between ,in ,like等運算符的查詢中。

index(重要)
關鍵字:條件是出現在索引樹中的節點的,可能沒有完全匹配索引。
索引全表掃描,把索引從頭到尾掃一遍,常見於使用索引列就可以處理不需要讀取數據文件的查詢、可以使用索引排序或者分組的查詢。

all(重要)
這個就是全表掃描數據文件,然后再在server層進行過濾返回符合要求的記錄。

possible_keys、key、key_len、ref、rows就不講了,直接講最后一個extra。
extra
這個列包含不適合在其他列中顯示單十分重要的額外的信息,這個列可以顯示的信息非常多,有幾十種,這里寫常見的幾種。
no tables used
表示不帶from字句的查詢,使用not in()形式子查詢或not exists運算符的連接查詢,這種叫做反連接。一般連接查詢是先查詢內表,再查詢外表,反連接就是先查詢外表,再查詢內表。
using filesort(重要)
排序時無法使用到索引時,就會出現這個,常見於order by和group by語句中。
using index(重要)
查詢時不需要回表查詢,直接通過索引就可以獲取查詢的數據。
using where(重要)
通常type類型為all,記錄並不是所有的都滿足查詢條件,通常有where條件,並且一般沒索引或者索引失效。
講完分析索引的參數后,現在老劉講一些索引失效的情況,大家一定要用心記住,老劉也記了好幾遍!
索引失效分析
-
一般SQL語句查詢采用全值匹配,資料上叫全值匹配我最愛。
-
最左前綴法則,對於組合索引而言,查詢從索引的最左前列開始,並且不能跳過索引中的列不然就會失效。
現在舉一個帶頭的索引斷(帶頭索引生效,其他索引失效)的例子:
-
不要在索引上做計算,例如計算、函數、自動/手動類型轉換,不然會導致索引失效而轉向全表掃描。
-
范圍條件右邊的列失效,就是不能繼續使用索引中范圍條件(bettween、<、>、in等)右邊的列。
-
盡量使用覆蓋索引(只查詢索引的列),也就是索引列和查詢列一致,減少select *。
-
索引字段上不要使用不等,索引字段上使用(!= 或者 < >)判斷時,會導致索引失效而轉向全表掃描。
-
主鍵索引字段上不可以判斷null,索引字段上使用 is null 判斷時,可使用索引。
-
索引字段使用like以通配符開頭(‘%字符串’)時,會導致索引失效而轉向全表掃描。like要以通配符結束相當於范圍查找,索引不會失效。
-
索引字段是字符串時,要加單引號,否則會導致索引失效而轉向全表掃描。
-
索引字段不要使用or,否則會導致索引失效而轉向全表掃描。
總結
這篇內容大家一定要跟着老劉練習,光看不練等於白學!盡管當前水平可能不及各位大佬,但老劉會努力變得更加優秀,讓各位小伙伴自學從此不求人!
如果有相關問題,聯系公眾號:努力的老劉。文章都看到這了,點贊關注支持一波!