數據庫只是增刪查改嗎?你瞭解索引嗎?

START

在這裏插入圖片描述

索引機制

前言:數據庫和數據庫索引這兩個東西是在服務器端開發領域應用最爲廣泛的兩個概念,熟練使用數據庫和數據庫索引是後端開發人員在行業內生存的必備技能。數據庫索引是用來提高數據庫表的數據查詢速度的。一個最優的索引能夠輕易的將查詢性能提高好幾個數量級

索引定義:

數據庫索引:屎對數據庫表中要查詢的字段簡歷索引其實就是吧該字段按照一定的方式排序的結構。

索引的作用和優點:

  1. 能夠大大的提高數據的查詢檢索速度
  2. 通過創建唯一性索引可以保證數據庫中每一行的唯一性
  3. 可以加速表和表之間的連接,特別是在實現數據的參考完整性方面特別有意義。
  4. 在使用分組和排序子句進行數據檢索時,同樣可以顯著減少查詢中分組和排序的時間。
  5. 通過使用索引,可以在查詢的過程中,使用查詢優化器,提高系統的性能。

索引的弊端和缺點:

  1. 索引會佔用一部分存儲空間,尤其在數據量很大的時候佔用的存儲空間可是很客觀的;
  2. 一旦對數據進行了插入、刪除、修改等操作,要對索引進行動態的維護。

但是總的來說利還是大於弊的,所以我們設計數據庫的時候需要善於利用索引,善於優化索引。

什麼地方該用索引,什麼地方應該避免使用索引?

使用索引:

  1. 在數據量超過幾百行之後就應該考慮建立索引,在主鍵上建立索引,保證數據的唯一性和組織表中的數據排列結構
  2. 在經常使用到的查詢列上建立索引,比如 where name = “wang” ,經常做這樣的查詢,那麼name上就應該建立索引
  3. 在經常進行範圍查詢的列上建立索引(可以建立聚簇索引,讓索引的順序和數據的物理存放順序一致,這樣大大的加快的查找的速度,變隨機查找爲順序查找)
  4. 在經常用在連接的列上,在連接字段列上建立索引,這些列主要是一些外鍵,可以加快連接的速度;
  5. 在經常需要排序的列上創建索引,因爲索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;

不該使用索引

  1. 數據量太小不要建立索引,因爲維護的代價要高於建立索引之後優化的代價
  2. 經常頻繁更新的列不要建立索引,因爲一旦更新,就要對索引也要隨之更新,如果更新的代價比查詢的代價高,那就不要建立索引
  3. 不經常被引用、查詢的列不要建立索引,因爲沒有必要
  4. 對於那些列的取值很少(比如性別),或者text等類型的大文本字段不要建立索引,大文本字段的索引也會很長,影響查詢。

索引的建立方法

普通索引

創建索引

這是最基本的索引,它沒有任何限制。它有以下幾種創建方式:

CREATE INDEX indexName ON mytable(username(length));
create index myDeptIndex on detail(dept_id);

如果是CHAR,VARCHAR類型,length可以小於字段實際長度;如果是BLOB和TEXT類型,必須指定length。

修改表結構(添加索引)

ALTER table tableName ADD INDEX indexName(columnName)

創建表的時候直接指定

CREATE TABLE mytable( 
ID INT NOT NULL, 
username VARCHAR(16) NOT NULL, 
INDEX [indexName] (username(length)) 
); 

刪除索引的語法

DROP INDEX [indexName] ON mytable;

唯一索引

它與前面的普通索引類似,不同的就是:索引列的值必須唯一,但允許有空值。如果是組合索引,則列
值的組合必須唯一。它有以下幾種創建方式:

創建索引

CREATE UNIQUE INDEX indexName ON mytable(username(length))

修改表結構

ALTER table mytable ADD UNIQUE [indexName] (username(length))

創建表的時候直接指定

CREATE TABLE mytable( 
ID INT NOT NULL, 
username VARCHAR(16) NOT NULL, 
UNIQUE [indexName] (username(length)) 
); 

使用ALTER 命令添加和刪除索引

有四種方式來添加數據表的索引:

  • ALTER TABLE tbl_name ADD PRIMARY KEY (column_list):

    該語句添加一個主鍵,這意味着索引值必須是唯一的,且不能爲NULL。

  • ALTER TABLE tbl_name ADD UNIQUE index_name (column_list): 這條語句創建索引的值必須是唯一的(除了NULL外,NULL可能會出現多次)。

  • ALTER TABLE tbl_name ADD INDEX index_name (column_list): 添加普通索引,索引值可出現多次。

  • ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list):該語句指定了索引爲FULLTEXT ,用於全文索引。

以下實例爲在表中添加索引。

mysql> ALTER TABLE testalter_tbl ADD INDEX (c);

你還可以在 ALTER 命令中使用 DROP 子句來刪除索引。嘗試以下實例刪除索引

mysql> ALTER TABLE testalter_tbl DROP INDEX c;

使用 ALTER 命令添加和刪除主鍵

主鍵只能作用於一個列上,添加主鍵索引時,你需要確保該主鍵默認不爲空(NOT NULL)。實例如下:

mysql> ALTER TABLE testalter_tbl MODIFY i INT NOT NULL;
mysql> ALTER TABLE testalter_tbl ADD PRIMARY KEY (i);

MySQL數據庫索引優化策略

1、索引列上不能使用表達式或者函數 **

例子:select ...... from product where to_days(out_date) - to_days(current_data)<=30 to_days
就是使用了函數,out_date就是索引列。
優化後:select ...... from product where out_date<=data_add(current_data,interval 30 day)
這樣對out_date索引列就沒有使用函數。
2、聯合索引,如何選擇索引的順序

  • 經常會被使用到的列優先
  • 選擇性高的列優先
  • 寬度小的列優先

3、索引不會包含有NULL值的列 **
只要列中包含有NULL值都將不會被包含在索引中,複合索引中只要有一列含有NULL值,那麼這一列對
於此複合索引就是無效的。所以我們在數據庫設計時不要讓字段的默認值爲NULL。
4、索引列排序 *
MySQL查詢只使用一個索引,因此如果where子句中已經使用了索引的話,那麼order by中的列是不會
使用索引的。因此數據庫默認排序可以符合要求的情況下不要使用排序操作;儘量不要包含多個列的排序,如果需要最好給這些列創建複合索引。
5、like語句操作 **

一般情況下不鼓勵使用like操作,如果非使用不可,如何使用也是一個問題。like “%aaa%” 不會使用索引而like “aaa%”可以使用索引。

eg:最後說一下:MySQL只對一下操作符才使用索引:<、<=、=、>、>=、between、in以及某些時候的
like(不以通配符%或_開頭的情形)。而理論上每張表裏面最多可創建16個索引。

索引原理

索引根據其構造結構可以分爲 : B-tree索引, B+tree索引, Hash索引,全文索引,空間數據索引(R-Tree),分行樹索引(TokuDB中使用)
先介紹幾種樹的概念:
B樹是二叉的排序樹,也叫二叉查找樹
紅黑樹是B樹的變種,是平衡的二叉排序樹
B-Tree 也是B樹的改進,而不過二叉變成了多叉,而且非葉子節點中也存儲了數據,搜索有可能到非葉結點就結束。
B+Tree 是B-tree的變種,所有的關鍵字都出現在葉子節點上,一次查找搜索必然是到葉子節點上才結束的。

B-tree 索引:

B-tree 是一種平衡的多叉排序樹,,,B-Tree它的特點如下:(M代表着階數,代表着一個節點最多有多少個孩子節點,例如M階B樹代表着該B樹的節點的孩子節點最多有M個)

  1. 定義任意非葉子結點最多隻有M個兒子;且M>2;

  2. 根結點的兒子數爲[2, M];

  3. 除根結點以外的非葉子結點的兒子數爲[M/2, M];

  4. 每個結點存放至少M/2-1(取上整)和至多M-1個關鍵字;(至少2個關鍵字)

  5. 非葉子節點的關鍵字個數 = 指向兒子的指針個數 - 1;

  6. 非葉子結點的指針:P[1], P[2], …, P[M];其中P[1]指向關鍵字小於K[1]的子樹,P[M]指向關鍵字大於K[M-1]的子樹,其它P[i]指向關鍵字屬於(K[i-1], K[i])的子樹;

  7. 所有的葉子節點位於同一層

B-Tree的特性:

  1. 關鍵字集合分佈在整棵樹中,
  2. 任何關鍵字出現且只出現在一個節點中
  3. 搜索有可能在非葉子節點中結束
  4. 搜索性能等價於做二分查找,做一次查找最大的次數爲 h 次,h爲B-tree的深度。

img

在數據庫中B-Tree索引的實現:

  1. 根節點常駐內存
  2. 根節點和非葉子節點的槽中存放了指向下一個子節點的指針,每個頁中存放着一些關鍵字,與指針相對應,定義了子節點中值的上限與下限,存儲引擎根據這些指針向下層查找, 但是葉子節點中只存放數據的物理地址,不再存放指針。
  3. 將每一個節點設定爲一個頁的大小,這樣只需要一次I/O就可以讀取一個節點的內容,(這是因爲頁是計算機管理存儲器的邏輯塊,硬件和操作系統在進行內存和磁盤上的數據交換時往往以一個頁作爲基本單位)
  4. 在葉節點和非葉子節點中,都存儲了關鍵字(該關鍵字裏包含了指向該索引數據本身的物理地址),在一次查找中,給定了某個關鍵字,如果在任何節點找到了該關鍵字(包括非葉結點)則就可以根據找到的關鍵字讀取到該關鍵字所指向的實際數據。

B+tree 索引: 是B-Tree的變種

大部分的定義和B-Tree相同,但是它有獨特於B-tree的地方,

  1. 非葉結點的子樹指針和關鍵字個數相同
  2. 非葉子結點的子樹指針P[i],指向關鍵字值屬於[K[i], K[i+1])的子樹(B-樹是開區間)
  3. 所有的葉子節點增加了一個指針,指針指向相鄰的葉子節點。
  4. 所有的關鍵字都在葉子節點中出現

B+Tree的特點

  1. 所有的關鍵字都出現在葉子節點中(稠密索引),而且葉子節點中的關鍵字恰好都是有序的
  2. 不可能在非葉子節點查找成功,這是因爲非葉子節點中存儲的仍舊是索引,並沒有存儲實際的數據或者指向實際數據的物理地址,在葉子節點才存放的是實際的數據或者實際數據的物理地址。
  3. 查找方式有兩種: 一種是從根節點進行查找,另一種是可以從葉子節點的開頭開始查找,因爲葉子節點中存儲了指向下一個葉子節點的指針,而且在數據庫的實現中,葉子節點在實際的物理存儲中是順序存放的,也就是葉子節點都是集中在一塊存儲區域內存放的(這樣的好處是大大提高了區間查詢效率)。

B+Tree 在 MySQL中的實現。

MySQL 中 的 InnoDB和MyISAM存儲引擎使用的就是B+Tree的實現方案:
在InnoDB中,數據的物理存放順序是按照設定聚簇索引的列的順序進行組織的(實質上是按照主鍵的順序組織數據),聚簇索引(一定包含主鍵,但也可能是主鍵和其他列的複合索引),對於InnoDB中來說,它的索引文件和數據文件是同一個文件,所以讀取進來的頁中(也就是一個節點)包含了key和data(key 爲索引,data爲實際的數據)
{
同時,對於聚簇索引來說, key = 索引鍵值;data = 實際數據本身
對於非聚簇索引,key = 索引鍵值, data = 聚簇索引的值
}

B+Tree 和B-Tree的性能比較?

  1. 相對來說 ,B-Tree鍵值只在索引中出現一次,比B+Tree能節省存儲空間;
  2. B-Tree樹的鍵值位置不定,使得在插入刪除操作中複雜度明顯增加,B+Tree的插入刪除操作性能比B-Tree更好
  3. B+Tree因爲葉子節點的物理存放是集中在一塊存儲區域的而且按順序存放,所以 B+Tree進行區間查詢的速度會更加的快。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章