Mysql底層知識進階-index原理

2. 索引

2.1 索引概述

MySQL官方對索引的定義爲:索引(index)是幫助MySQL高效獲取數據的數據結構(有序)。在數據之外,數據庫系統還維護者滿足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據, 這樣就可以在這些數據結構上實現高級查找算法,這種數據結構就是索引。如下面的==示意圖==所示 :

 

左邊是數據表,一共有兩列七條記錄,最左邊的是數據記錄的物理地址(注意邏輯上相鄰的記錄在磁盤上也並不是一定物理相鄰的)。爲了加快Col2的查找,可以維護一個右邊所示的二叉查找樹,每個節點分別包含索引鍵值和一個指向對應數據記錄物理地址的指針,這樣就可以運用二叉查找快速獲取到相應數據。

一般來說索引本身也很大,不可能全部存儲在內存中,因此索引往往以索引文件的形式存儲在磁盤上。索引是數據庫中用來提高性能的最常用的工具。

2.2 索引優勢劣勢

優勢

1) 類似於書籍的目錄索引,提高數據檢索的效率,降低數據庫的IO成本。

2) 通過索引列對數據進行排序,降低數據排序的成本,降低CPU的消耗。

劣勢

1) 實際上索引也是一張表,該表中保存了主鍵與索引字段,並指向實體類的記錄,所以索引列也是要佔用空間的。

2) 雖然索引大大提高了查詢效率,同時卻也降低更新表的速度,如對錶進行INSERT、UPDATE、DELETE。因爲更新表時,MySQL 不僅要保存數據,還要保存一下索引文件每次更新添加了索引列的字段,都會調整因爲更新所帶來的鍵值變化後的索引信息。

 

2.3 索引結構

索引是在MySQL的存儲引擎層中實現的,而不是在服務器層實現的。所以每種存儲引擎的索引都不一定完全相同,也不是所有的存儲引擎都支持所有的索引類型的。MySQL目前提供了以下4種索引:

  • BTREE 索引 : 最常見的索引類型,大部分索引都支持 B 樹索引。

  • HASH 索引:只有Memory引擎支持 , 使用場景簡單 。

  • R-tree 索引(空間索引):空間索引是MyISAM引擎的一個特殊索引類型,主要用於地理空間數據類型,通常使用較少,不做特別介紹。

  • Full-text (全文索引) :全文索引也是MyISAM的一個特殊索引類型,主要用於全文索引,InnoDB從Mysql5.6版本開始支持全文索引。

MyISAM、InnoDB、Memory三種存儲引擎對各種索引類型的支持

索引 InnoDB引擎 MyISAM引擎 Memory引擎
BTREE索引 支持 支持 支持
HASH 索引 不支持 不支持 支持
R-tree 索引 不支持 支持 不支持
Full-text 5.6版本之後支持 支持 不支持

我們平常所說的索引,如果沒有特別指明,都是指B+樹(多路搜索樹,並不一定是二叉的)結構組織的索引。其中聚集索引、複合索引、前綴索引、唯一索引默認都是使用 B+tree 索引,統稱爲 索引。

 

2.3.1 BTREE 結構

BTree又叫多路平衡搜索樹,一顆m叉的BTree特性如下:

  • 樹中每個節點最多包含m個孩子。

  • 除根節點與葉子節點外,每個節點至少有[ceil(m/2)]個孩子。

  • 若根節點不是葉子節點,則至少有兩個孩子。

  • 所有的葉子節點都在同一層。

  • 每個非葉子節點由n個key與n+1個指針組成,其中[ceil(m/2)-1] <= n <= m-1

 

以5叉BTree爲例,key的數量:公式推導[ceil(m/2)-1] <= n <= m-1。所以 2 <= n <=4 。當n>4時,中間節點分裂到父節點,兩邊節點分裂。

插入 C N G A H E K Q M F W L T Z D P R X Y S 數據爲例。

演變過程如下:

1). 插入前4個字母 C N G A

2). 插入H,n>4,中間元素G字母向上分裂到新的節點

3). 插入E,K,Q不需要分裂

4). 插入M,中間元素M字母向上分裂到父節點G

5). 插入F,W,L,T不需要分裂

6). 插入Z,中間元素T向上分裂到父節點中

7). 插入D,中間元素D向上分裂到父節點中。然後插入P,R,X,Y不需要分裂

8). 最後插入S,NPQR節點n>5,中間節點Q向上分裂,但分裂後父節點DGMT的n>5,中間節點M向上分裂

到此,該BTREE樹就已經構建完成了, BTREE樹 和 二叉樹 相比, 查詢數據的效率更高, 因爲對於相同的數據量來說,BTREE的層級結構比二叉樹小,因此搜索速度快。

 

2.3.3 B+TREE 結構

B+Tree爲BTree的變種,B+Tree與BTree的區別爲:

1). n叉B+Tree最多含有n個key,而BTree最多含有n-1個key。

2). B+Tree的葉子節點保存所有的key信息,依key大小順序排列。

3). 所有的非葉子節點都可以看作是key的索引部分。

由於B+Tree只有葉子節點保存key信息,查詢任何key都要從root走到葉子。所以B+Tree的查詢效率更加穩定。

2.3.3 MySQL中的B+Tree

MySql索引數據結構對經典的B+Tree進行了優化。在原B+Tree的基礎上,增加一個指向相鄰葉子節點的鏈表指針,就形成了帶有順序指針的B+Tree,提高區間訪問的性能。

MySQL中的 B+Tree 索引結構示意圖:

 

 

 

 

 

 

 

 

 

 

2.4 索引分類

1) 單值索引 :即一個索引只包含單個列,一個表可以有多個單列索引

2) 唯一索引 :索引列的值必須唯一,但允許有空值

3) 複合索引 :即一個索引包含多個列

 

2.5 索引語法

索引在創建表的時候,可以同時創建, 也可以隨時增加新的索引。

準備環境:

create database demo_01 default charset=utf8mb4;
​
use demo_01;
​
CREATE TABLE `city` (
  `city_id` int(11) NOT NULL AUTO_INCREMENT,
  `city_name` varchar(50) NOT NULL,
  `country_id` int(11) NOT NULL,
  PRIMARY KEY (`city_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
​
CREATE TABLE `country` (
  `country_id` int(11) NOT NULL AUTO_INCREMENT,
  `country_name` varchar(100) NOT NULL,
  PRIMARY KEY (`country_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
​
​
insert into `city` (`city_id`, `city_name`, `country_id`) values(1,'西安',1);
insert into `city` (`city_id`, `city_name`, `country_id`) values(2,'NewYork',2);
insert into `city` (`city_id`, `city_name`, `country_id`) values(3,'北京',1);
insert into `city` (`city_id`, `city_name`, `country_id`) values(4,'上海',1);
​
insert into `country` (`country_id`, `country_name`) values(1,'China');
insert into `country` (`country_id`, `country_name`) values(2,'America');
insert into `country` (`country_id`, `country_name`) values(3,'Japan');
insert into `country` (`country_id`, `country_name`) values(4,'UK');

2.5.1 創建索引

語法 :

CREATE  [UNIQUE|FULLTEXT|SPATIAL]  INDEX index_name 
[USING  index_type]
ON tbl_name(index_col_name,...)
​
​
index_col_name : column_name[(length)][ASC | DESC]

示例 : 爲city表中的city_name字段創建索引 ;

 

2.5.2 查看索引

語法:

show index  from  table_name;

示例:查看city表中的索引信息;

 

 

2.5.3 刪除索引

語法 :

DROP  INDEX  index_name  ON  tbl_name;

示例 : 想要刪除city表上的索引idx_city_name,可以操作如下:

 

2.5.4 ALTER命令

1). alter  table  tb_name  add  primary  key(column_list); 
​
    該語句添加一個主鍵,這意味着索引值必須是唯一的,且不能爲NULL
    
2). alter  table  tb_name  add  unique index_name(column_list);
    
    這條語句創建索引的值必須是唯一的(除了NULL外,NULL可能會出現多次)
    
3). alter  table  tb_name  add  index index_name(column_list);
​
    添加普通索引, 索引值可以出現多次。
    
4). alter  table  tb_name  add  fulltext  index_name(column_list);
    
    該語句指定了索引爲FULLTEXT, 用於全文索引

 

2.6 索引設計原則

索引的設計可以遵循一些已有的原則,創建索引的時候請儘量考慮符合這些原則,便於提升索引的使用效率,更高效的使用索引。

  • 對查詢頻次較高,且數據量比較大的表建立索引。

  • 索引字段的選擇,最佳候選列應當從where子句的條件中提取,如果where子句中的組合比較多,那麼應當挑選最常用、過濾效果最好的列的組合。

  • 使用唯一索引,區分度越高,使用索引的效率越高。

  • 索引可以有效的提升查詢數據的效率,但索引數量不是多多益善,索引越多,維護索引的代價自然也就水漲船高。對於插入、更新、刪除等DML操作比較頻繁的表來說,索引過多,會引入相當高的維護代價,降低DML操作的效率,增加相應操作的時間消耗。另外索引過多的話,MySQL也會犯選擇困難病,雖然最終仍然會找到一個可用的索引,但無疑提高了選擇的代價。

  • 使用短索引,索引創建之後也是使用硬盤來存儲的,因此提升索引訪問的I/O效率,也可以提升總體的訪問效率。假如構成索引的字段總長度比較短,那麼在給定大小的存儲塊內可以存儲更多的索引值,相應的可以有效的提升MySQL訪問索引的I/O效率。

  • 利用最左前綴,N個列組合而成的組合索引,那麼相當於是創建了N個索引,如果查詢時where子句中使用了組成該索引的前幾個字段,那麼這條查詢SQL可以利用組合索引來提升查詢效率。

創建複合索引:

	CREATE INDEX idx_name_email_status ON tb_seller(NAME,email,STATUS);

就相當於
	對name 創建索引 ;
	對name , email 創建了索引 ;
	對name , email, status 創建了索引 ;

 

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