1、索引介紹mysql
索引可讓數據庫加快查詢速度,可是卻會減慢數據的插入速度。由於每次插入一個數據,都要從新處理一次索引。算法
索引是利用不斷縮小查詢範圍,去除不相關數據來找到目標數據。sql
索引使用B+樹算法,把索引分層次存儲,每次加載一個磁盤塊進入內存中(根節點),進行比較,找到對應範圍內的指針,而後再去加載另外一塊磁盤塊(枝節點),找到所對應的指針,一直找到最底層葉子節點。數據庫
如上圖是一顆B+樹,最上層是根節點,中間是枝節點,最下層是葉子節點。如今假設查找數據項28,先把磁盤塊1加載到內存中,數據項28跟數據項17和數據項35比較,能夠看到28處於中間,那麼就能夠去除掉小於17和大於35的部分了。而後,也找到了P2,P2指針對應的磁盤塊3。再把磁盤塊3加載到內存中,28在26和30之間,這樣又除去了小於26和大於30的部分。也找到了指針P2,以及P2指示的數據塊8,再把磁盤塊8加載到內存中,找到了數據塊28。函數
B+樹的性質:spa
索引的最左匹配特性:B+樹搜索數據時,是從左往右比對,而後根據表中字段順序依次比對的。指針
索引的兩大類型:blog
#咱們能夠在建立上述索引的時候,爲其指定索引類型,分兩類hash類型的索引:查詢單條快,範圍查詢慢排序
btree類型的索引:b+樹,層數越多,數據量指數級增加(咱們就用它,由於innodb默認支持它)索引
#不一樣的存儲引擎支持的索引類型也不同
InnoDB 支持事務,支持行級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
MyISAM 不支持事務,支持表級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
2、彙集索引和輔助索引
數據庫中的索引能夠分爲彙集索引和輔助索引:
(1)彙集索引和輔助索引的相同點是:無論是彙集索引仍是輔助索引,其內部都是B+樹形式,就是樹的高度(或層數)是同樣的,葉子結點中存放着全部的數據。
(2)彙集索引和輔助索引的不一樣點是:葉子節點存放的是不是一整行的信息。(彙集索引存放的是一整行,輔助索引存放的是一部分。)
1.彙集索引
彙集索引就是不可爲空且是惟一的一個字段,最好這個字段在內存中所佔空間越小越好。
彙集索引的好處之一:它對主鍵的排序查找和範圍查找速度很是快,葉子節點的數據就是用戶所要查詢的數據。
彙集索引的好處之二:範圍查詢(range query),即若是要查找主鍵某一範圍內的數據,經過葉子節點的上層中間節點就能夠獲得頁的範圍,以後直接讀取數據頁便可
輔助索引的葉子節點中存儲的是主鍵,而後再使用這個主鍵走一遍「根節點-->枝節點-->葉子結點」的過程。這樣作會增長一倍的IO操做,可是相對於從頭走到尾那樣的查詢,而且每次都要操做IO的方式,這樣作是完勝的。
3、實際操做
普通索引INDEX:加速查找
惟一索引:
-主鍵索引PRIMARY KEY:加速查找+約束(不爲空、不能重複)
-惟一索引UNIQUE:加速查找+約束(不能重複)
聯合索引:
-PRIMARY KEY(id,name):聯合主鍵索引
-UNIQUE(id,name):聯合惟一索引
-INDEX(id,name):聯合普通索引
彙集索引:
(1) 建立表時,直接建立出來:create table t2(id int primary key,name char(10),age int, class int ,index in_age(age));
惟一索引:
(1) 表建立好後,再去添加惟一索引: alter table t2 add unique key un_class(class);
輔助索引:
(1) 表建立好後,再去添加輔助索引:create index in_name on t2(name);
彙集索引:
(1)alter table t2 drop primary key;
輔助索引:
(1) drop index in_name on t2;
(2) alter table t2 drop index in_name;
惟一索引:
(1)alter table t2 drop index un_class;
4、正確使用索引
並非說咱們建立了索引就必定會加快查詢速度,若想利用索引達到預想的提升查詢速度的效果,咱們在添加索引時,必須遵循如下問題
一、 範圍問題,或者說條件不明確,條件中出現這些符號或關鍵字:>、>=、<、<=、!= 、between...and...、like、大於號、小於號
例如:若是寫成where id >1 and id <1000000;會發現,隨着你範圍的增大,速度會愈來愈慢,會成倍的體現出來。
二、 不等於!=,比等於要多費時間。
三、 between ...and... 和大於小於同樣,範圍越小查詢速度越快。
四、 like匹配的值裏若是後面沒有%,那麼和=是同樣的,速度很快。若是有%,那麼速度也很快,會去迅速匹配相應的記錄,可是若是%在開始位置,就至關於這個值會與每行記錄進行比較一下。因此%在開始位置時,會使查詢速度變慢。
五、 =和in能夠亂序:
好比a = 1 and b = 2 and c = 3 ,a,b,c的位置能夠隨意排;
in (b,c,a)in後面的a,b,c也是能夠打亂順序的。
六、 索引列不能參與計算,保持列「乾淨」:
where id = 1000;這樣的條件,能夠很容易的對比出來,而後取出這一行的記錄。
可是,where id*3 = 10000,這樣的計算就會致使每次對比前都得先計算一下id的值是多少,所以就不能發揮出索引快速查詢的做用了。
把上面的條件寫成 where id = 3000/3;你會發現速度變得很快,由於等於號後面的數字,是在比較以前就計算出來了,不須要每次都計算一次每次都計算一次了,跟直接等於一個常數是同樣的,因此很快。結論是不要讓你的索引字段參與到計算中。
七、 and和or
a=2 and b>3 and c=4,像這樣and的工做原理是,先按照最左原則,從左往右先找出區分度高的把範圍縮小,而後再去查找其餘的條件。
區分度=count(distinct 字段)/count(*) 值越大,區分度越高,值越小,區分度越低。
a=2 or b>3 or c=4,像這樣or的工做原理是,按照最左原則,先判斷第一個條件是否成立,若是成立那麼就中止,不成立的話,再對比第二個,這樣依次比較下去。
八、 最左前綴匹配原則,很是重要的原則,對於組合索引mysql會一直向右匹配直到遇到範圍查詢(>、<、between、like)就中止匹配(指的是範圍大了,有索引速度也慢),好比a = 1 and b = 2 and c > 3 and d = 4 若是創建(a,b,c,d)順序的索引,d是用不到索引的,若是創建(a,b,d,c)的索引則均可以用到,a,b,d的順序能夠任意調整。
九、 其餘狀況
- 使用函數
select * from tb1 where reverse(email) = 'egon';
- 類型不一致
若是列是字符串類型,傳入條件時必須用引號引發來,否則報錯: Unknown column 'xx' in 'where clause'
select * from tb1 where email = 999;
#排序條件爲索引,則select字段必須也是索引字段,不然沒法命中
- order by
select name from s1 order by email desc;
當根據索引排序時候,select查詢的字段若是不是索引,則速度仍然很慢。這與B+樹有關,普通索引的葉子節點中只是保存了彙集索引的值,因此會回表。
select email from s1 order by email desc;
特別的:若是對主鍵排序,則仍是速度很快:
select * from tb1 order by nid desc;
由於在B+樹的葉子節點中,存儲的是那一行記錄的索引,找到了主鍵索引就找到了行記錄。
- 組合索引最左前綴
若是組合索引爲:(name,email)
name and email -- 命中索引
name -- 命中索引
email -- 未命中索引
- count(1)或count(列)代替count(*)在mysql中沒有差異了
- create index xxxx on tb(title(19)) #text類型,必須制定長度。
- 避免使用select *
- count(1)或count(列) 代替 count(*)
- 建立表時儘可能時 char 代替 varchar
- 表的字段順序固定長度的字段優先
- 組合索引代替多個單列索引(常用多個條件查詢時)
- 儘可能使用短索引
- 使用鏈接(JOIN)來代替子查詢(Sub-Queries)
- 連表時注意條件類型需一致- 索引散列值(重複少)不適合建索引,例:性別不適合
5、聯合索引和覆蓋索引
一、聯合索引
mysql> create table t( -> a int, -> b int, -> primary key(a), -> key idx_a_b(a,b) -> );
那麼什麼時候須要使用聯合索引呢?在討論這個問題以前,先來看一下聯合索引內部的結果。從本質上來講,聯合索引就是一棵B+樹,不一樣的是聯合索引的鍵值得數量不是1,而是>=2。接着來討論兩個整型列組成的聯合索引,假定兩個鍵值得名稱分別爲a、b如圖:
能夠看到這與咱們以前看到的單個鍵的B+樹並無什麼不一樣,鍵值都是排序的,經過葉子結點能夠邏輯上順序地讀出全部數據,就上面的例子來講,即(1,1),(1,2),(2,1),(2,4),(3,1),(3,2),數據按(a,b)的順序進行了存放。
所以,對於查詢select * from table where a=xxx and b=xxx, 顯然是可使用(a,b) 這個聯合索引的,對於單個列a的查詢select * from table where a=xxx,也是可使用(a,b)這個索引的。
但對於b列的查詢select * from table where b=xxx,則不可使用(a,b) 索引,其實你不難發現緣由,葉子節點上b的值爲一、二、一、四、一、2顯然不是排序的,所以對於b列的查詢使用不到(a,b) 索引。
注意創建聯合索引的一個原則:索引是有個最左匹配的原則的,因此建聯合索引的時候,將區分度高的放在最左邊,依次排下來,範圍查詢的條件儘量的日後邊放。
聯合索引的第二個好處是在第一個鍵相同的狀況下,已經對第二個鍵進行了排序處理,例如在不少狀況下應用程序都須要查詢某個用戶的購物狀況,並按照時間進行排序,最後取出最近三次的購買記錄,這時使用聯合索引能夠幫咱們避免多一次的排序操做,由於索引自己在葉子節點已經排序了。
2.覆蓋索引
InnoDB存儲引擎支持覆蓋索引(covering index,或稱索引覆蓋),即從輔助索引中就能夠獲得查詢記錄,而不須要查詢彙集索引中的記錄。
使用覆蓋索引的一個好處是:輔助索引不包含整行記錄的全部信息,故其大小要遠小於彙集索引,所以能夠減小大量的IO操做。