(三十八)索引

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

  1. 索引字段要儘可能的小由於磁盤塊的大小是固定的,只有索引字段越小,能夠存儲的越多。

索引的最左匹配特性B+樹搜索數據時,是從左往右比對,而後根據表中字段順序依次比對的。指針

索引的兩大類型:blog

#咱們能夠在建立上述索引的時候,爲其指定索引類型,分兩類hash類型的索引:查詢單條快,範圍查詢慢排序

btree類型的索引:b+樹,層數越多,數據量指數級增加(咱們就用它,由於innodb默認支持它)索引

 

#不一樣的存儲引擎支持的索引類型也不同

InnoDB 支持事務,支持行級別鎖定,支持 B-treeFull-text 等索引,不支持 Hash 索引;

MyISAM 不支持事務,支持表級別鎖定,支持 B-treeFull-text 等索引,不支持 Hash 索引;

 

2、彙集索引和輔助索引

 

數據庫中的索引能夠分爲彙集索引和輔助索引:

 

(1)彙集索引和輔助索引的相同點是:無論是彙集索引仍是輔助索引,其內部都是B+樹形式,就是樹的高度(或層數)是同樣的,葉子結點中存放着全部的數據。

 

(2)彙集索引和輔助索引的不一樣點是:葉子節點存放的是不是一整行的信息。(彙集索引存放的是一整行,輔助索引存放的是一部分。)

 


1.彙集索引

 

彙集索引就是不可爲空且是惟一的一個字段,最好這個字段在內存中所佔空間越小越好。

 

彙集索引的好處之一:它對主鍵的排序查找和範圍查找速度很是快,葉子節點的數據就是用戶所要查詢的數據

 

彙集索引的好處之二:範圍查詢(range query),即若是要查找主鍵某一範圍內的數據,經過葉子節點的上層中間節點就能夠獲得頁的範圍,以後直接讀取數據頁便可

 

  1. 輔助索引

 

輔助索引的葉子節點中存儲的是主鍵,而後再使用這個主鍵走一遍「根節點-->枝節點-->葉子結點」的過程。這樣作會增長一倍的IO操做,可是相對於從頭走到尾那樣的查詢,而且每次都要操做IO的方式,這樣作是完勝的。

 

3、實際操做

   普通索引INDEX:加速查找

惟一索引:

    -主鍵索引PRIMARY KEY:加速查找+約束(不爲空、不能重複)

   -惟一索引UNIQUE:加速查找+約束(不能重複)

 

聯合索引:

    -PRIMARY KEY(id,name):聯合主鍵索引

    -UNIQUE(id,name):聯合惟一索引

    -INDEX(id,name):聯合普通索引

 

  1. 建立索引

    彙集索引:

(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. 刪除索引:

彙集索引:

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類型,必須制定長度。

  1. 注意事項

- 避免使用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操做。

相關文章
相關標籤/搜索