索引的底層結構以及使用


前言
索引是一種提高查詢效率的數據結構(B樹或者是哈希結構)索引是創建在數據庫表中,是對數據庫表中的一列或者多列值的進行排序的一個結果,好處就是提高查詢效率。

索引的創建和刪除

建表時創建索引

create table user (
name VARCHAR(20) ,
sex BOOLEAN ,
[UNIQUE][FULLTEXT][PRIMARY KEY]INDEX index_name(id)
);

給已存在的表創建索引

  • 添加PRIMARY KEY(主鍵索引)
          ALTER TABLE table_name ADD PRIMARY KEY ( column )
  • 添加UNIQUE(唯一索引)
          ALTER TABLE table_name ADD UNIQUE ( column )
  • 添加INDEX(普通索引)
          ALTER TABLE table_name ADD INDEX index_name ( column )
  • 添加FULLTEXT(全文索引)
          ALTER TABLE table_name ADD FULLTEXT ( column)
  • 添加多列索引
          ALTER TABLE table_name ADD INDEX index_name ( column1, column2, column3 )

刪除索引

  • alter table table_name drop index_name
  • drop index 索引名 on 表名

索引的分類

索引 功能
普通索引 沒有任何限制條件,可以給任何類型的字段創建普通索引
唯一性索引 使用 UNIQUE 修飾的字段,值不能夠重複,主鍵索引就隸屬於唯一性索引
主鍵索引 使用 Primary Key 修飾的字段會自動創建索引
單列索引 在一個字段上創建索引
多列索引 在表的多個字段上創建索引
全文索引 使用 FULLTEXT 參數可以設置全文索引,只支持 CAHR,VARCHAR和TEXT類型的字段上。常用於數據量較大的字符串類型上,可以提高查詢速度;只有 MyISAM存儲引擎支持

索引的底層結構(以InnoDB的索引結構爲例)

b樹(balance tree)和b+樹應用在數據庫索引,可以認爲是m叉的多路平衡查找樹,但是從理論上講,二叉樹查找速度和比較次數都是最小的,一個m階的多路平衡樹具有如下特徵:

  • 定義任意非葉子結點最多隻有M個兒子,且M>2;
  • 根結點的兒子數爲[2, M];
  • 除根結點以外的非葉子結點的兒子數爲[M/2, M],向上取整;
  • 非葉子結點的關鍵字個數=兒子數-1;
  • 所有葉子結點位於同一層;
  • k個關鍵字把節點拆成k+1段,分別指向k+1個兒子,同時滿足查找樹的大小關係。
    一、 B樹
    在這裏插入圖片描述
  • 關鍵字分佈在整顆樹中
  • 任何一個關鍵字出現且只出現在一個結點中
  • 搜索有可能在非葉子結點結束
  • 其搜索性能等價於在關鍵字全集內做一次二分查找
    二、B+樹
    在這裏插入圖片描述
  • 有n棵子樹的非葉子結點中含有n個關鍵字(b樹是n-1個),這些關鍵字不保存數據,只用來索引,所有數據都保存在葉子節點(b樹是每個關鍵字都保存數據)。
  • 所有的葉子結點中包含了全部關鍵字的信息,及指向含這些關鍵字記錄的指針,且葉子結點本身依關鍵字的大小自小而大順序鏈接。
  • 所有的非葉子結點可以看成是索引部分,結點中僅含其子樹中的最大(或最小)關鍵字。
  • 通常在b+樹上有兩個頭指針,一個指向根結點,一個指向關鍵字最小的葉子結點。
    同一個數字會在不同節點中重複出現,根節點的最大元素就是b+樹的最大元素。

B樹和B+樹的區別

  • B+樹的所有葉子節點連接到一條鏈表上,支持區間查找
  • B樹的所有節點不僅要存關鍵字,還要存儲和關鍵字對應的數據地址,B+樹的非葉子節點只存儲關鍵字,只有葉子節點存儲關鍵字和數據地址。
  • B+樹的層數較少,查找索引時I/O操作較少
  • B樹關鍵字在整個樹的每個節點都存在,誰離根節點近,誰搜索的速度就快
  • B+關鍵字都會出現在葉子節點上,非葉子節點只存關鍵字,意味着所有的記錄都在葉子節點上存儲,所有記錄搜索的時間是平均的。

由於磁盤的讀取也是按block塊操作的(內存是按page頁面操作的),
因此B-樹的節點大小一般設置爲和磁盤塊大小一致,這樣一個B-樹節點,
就可以通過一次磁盤I/O把一個磁盤塊的數據全部存儲下來,所以當使用B-樹存儲索引的時候,磁盤I/O的操作次數是最少的(MySQL的讀寫效率,主要集中在磁盤I/O上)。

三、系統底層結構
系統分爲用戶空間、內核空間兩部分。
用戶空間通過操作系統來控制計算機硬件中的磁盤來讀取數據,計算機硬件和操作系統之間數據傳輸是以塊爲單位的,操作系統和用戶空間是以頁來傳輸數據,塊爲頁的倍數。

在這裏插入圖片描述

  • 檢查where條件字段有沒有創建過索引,從磁盤上加載索引文件到內存上(這個過程會產生磁盤I/O,這個就是影響查詢最關鍵的東西)
  • 在內存中用索引文件的數據構造一棵二叉樹

SQL 的查表操作

  • 檢查where條件字段有沒有創建過索引,從磁盤上加載索引文件(以塊爲單位)到內存上(這個過程會產生磁盤I/O,這個就是影響查詢最關鍵的東西)
  • 在內存中用索引文件的數據構造一棵二叉樹
  • 先加載根節點到用戶空間,用戶空間判斷下一個需要加載的節點,從內存中再加載進來。
  • 直到找到葉子節點

索引的使用

我們通過一些例子來比使用索引的好處。這是後面例子中用的數據表。
在這裏插入圖片描述
Explain
explain顯示了mysql如何使用索引來處理select語句以及連接表。可以幫助選擇更好的索引和寫出更優化的查詢語句。
使用方法,在select語句前加上explain就可以了
關於explain 請參考我的另一篇博客:https://blog.csdn.net/Alyson_jm/article/details/83722001
沒有索引查詢
在這裏插入圖片描述
初始時,表裏只有三條數據,上面row = 3,表示當前查詢爲全表查詢。key = null,沒有使用索引。
有索引查詢
在這裏插入圖片描述
ID 爲主鍵,當前查詢用了主鍵查詢,row =1,提高了效率。

給經常作爲where過濾條件的字段和分組排序字段創建聯合索引

  • 根據聯合索引的第一個字段進行過濾得到一個結果集
  • 結果集已經拍好了序,直接從內存中拿出來,減少了外部排序

下面這個語句中,class_name 沒有創建索引,並且我們按照score排序,rows = 6,它使用了全表遍歷,並且使用了外部排序,這非常的耗費資源。

  • 按照class_stu進行全表查詢,得到一個結果集

  • 對結果集進行外部排序
    在這裏插入圖片描述
    創建聯合索引
    在這裏插入圖片描述

  • 根據索引樹得到一個結果集

  • 得到的這個結果集已經按照score排好了序。
    在這裏插入圖片描述

    要使用聯合索引,一定要先使用聯合索引的第一個字段
    雖然score建立了索引,但是它是索引的第二個字段,索引樹是按照聯合索引的第一個字段建立的,所以SQL選擇了全表查詢。
    在這裏插入圖片描述
    內連接查詢 在這裏插入圖片描述查詢過程

  • Mysql先比較哪個表小,從小表裏找到所有的記錄

  • 去大表裏取數據進行比較。

  • 大表決定了查詢的次數,小表決定了每次循環的查詢時間。
    在這個例子中就是先對class_stu 進行全表查詢,然後根據class_stu的值去student裏一個一個匹配(因爲大表student沒有加索引)
    在這裏插入圖片描述
    所以內連接查詢在大表里加索引,加快了匹配的效率。
    給大表增加索引
    在這裏插入圖片描述
    在這裏插入圖片描述
    加了索引之後大表student 就不是全表查詢了,加快了查詢效率。

    • 大表小表也不是絕對的。如果大表有過濾條件,那就判斷哪個開銷小哪個就是小表,如果大表的過濾條件有加索引,並且過濾掉後的數據比小表還少,那麼此時大表就變成了小表。
    • 當大表student有過濾條件時,SQL判斷student過濾後只有一條數據,就將student作爲小表,大表就變成了class_stu.根據student的數據對calss_stu一行一行匹配。
      在這裏插入圖片描述
    • 給class_stu的stu_name加索引,此時calss_stu 的rows = 3,比原來的rows = 8 來說效率提高了一點。
      在這裏插入圖片描述
      在這裏插入圖片描述
      3.左連接查詢
      左連接查詢是把左邊的數據全部拿出來,去和右邊進行匹配,給右表加索引會增加查詢效率。
      右表沒加索引
      在這裏插入圖片描述
      給表圖加上索引
      在這裏插入圖片描述
      4.右連接查詢
      右連接查詢和左連接查詢剛好相反,右邊的數據被全部拿出,去和左邊的表進行匹配,給左表加索引會增加查詢效率。
      在這裏插入圖片描述

索引的設計要求

  • 給經常作爲where過濾條件的字段和分組排序字段創建聯合索引。
  • 要使用聯合索引,一定要先使用聯合索引的第一個字段。
  • 一般給區分度高的字段創建索引。
  • 尤其是對於字符串類型的字段,創建索引的時候可以指定索引的長度,只用字符串的一部分來創建索引數據就可以啦。
  • 索引的數目不宜過多
  • 使用數據量少的索引(如前綴索引,主要針對字符串類型,字符串類型,儘量創建前綴索引)
  • 對於多列索引,優先指定最左邊的列集.

使用索引的注意事項

無法使用索引的情況

like “%XXX%” not in <> or

1、 like通配符放到前面是沒有索引的
當通配符在最前面表示前面任意什麼字符都可以,根據索引樹的結構來說,SQL不知道怎麼判斷,所以就放棄使用索引。
在這裏插入圖片描述
2、使用not in 無法用到索引
在這裏插入圖片描述
找不在某個集合裏面的元素還是要遍歷B樹裏所有的元素,直接全表查詢更方便。
3、使用!= 無法用到索引,同理<>也無法用到索引
在這裏插入圖片描述
4、使用or無法用到索引
通過or連接有多個查詢條件,一次查詢只能用一個索引,即使SQL使用了某個索引,也不可避免的要再進行一次全表查詢,降低了效率,所以SQL放棄了使用索引。
在這裏插入圖片描述

索引不宜過多
索引的數據結構是B樹,在查詢時會增加效率,但是在插入和更新數據的時候會降低效率,得不償失。

只select需要用到的字段,儘量不要用到
B+樹存儲的是索引的關鍵字,除了關鍵字還有主鍵值,通過主鍵值去主鍵索引樹(主鍵索引樹裏每個數據項不僅存儲主鍵值,還存儲主鍵對應的行的記錄),裏面查找需要的記錄。
用*查詢會先按照索引關鍵字找到對應的主鍵值,然後通過主鍵值進行主鍵索引,產生了二次索引。
需要查詢部分值的時候,可以建立聯合索引,將過濾條件用作聯合索引的第一個字段。

索引的長度最好限制一下
索引的長度如果太長,每一個節點裏存儲的索引數就比較少,增加了查找的次數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章