数据库索引详细介绍
數據庫索引
- 索引的定義
- 索引的作用
- B-Tree和B+Tree異同
- 什么場景不適合創建索引
- 什么樣的字段適合創建索引
- 索引的分類
- 1. 主鍵索引
- 2. 唯一索引
- 3. 常規索引
- 4. 全文索引
- 索引的不足
- 使用索引的細節問題
?\color{red}{\clubsuit}?
索引是面試中較常考的考點之一。
比如面試官會問你,索引為啥能提高查詢速度?如果不知道,那就往下看吧~
索引的定義
索引相當于一本書的目錄,通過目錄我們可以迅速定位書中要找的內容。MySQL中的索引也是一樣,它是一種幫助MySQL高效獲取數據的數據結構(樹)
索引怎么實現的?為什么用B+樹?
索引是數據庫中一個用于排序的數據結構,用來快速查詢數據庫中的數據。Mysql數據庫使用B+樹來實現索引的。B+樹的特點就是葉子節點包含了所有的關鍵字信息和data數據,非葉子節點只包含子節點的最大或者最小關鍵字,用來實現索引。
好處:既能實現快速查找,相比于B樹又節約了內存空間。
Mysql數據庫中的索引實現主要依賴于兩個存儲引擎,MyISAM和InnoDB,都是使用B+樹作為索引結構。區別就是MyISAM中使用B+樹的葉子節點的data域存放數據的內存地址,而InnoDB中樹的葉節點data域保存了完整的數據。
建索引的優缺點
優點:大大加快對數據的查詢速度
缺點:占物理空間,對數據庫進行增刪改的時候也要動態的維護索引。
索引的作用
?\color{green}{\diamondsuit}?提高查詢速度
?\color{blue}{\diamondsuit}?確保數據的唯一性
?\color{pink}{\diamondsuit}?可以加速表和表之間的連接,實現表和表之間的參照完整性
?\color{red}{\diamondsuit}?使用分組和排序子句進行數據檢索時,可以減少分組和排序的時間
?\color{grey}{\diamondsuit}?全文檢索字段進行搜索優化
索引如何提高查詢速度呢
假如我們有如下的一張表,在沒有引入索引之前,假如我們想查詢表中的一條年齡為20的數據,那么幾乎要遍歷完整個表才能查詢到這條數據;現在我們引入索引,并且以age列作為索引列來構建出一個二叉樹的索引結構來,具體的構造過程是先把表中第一行的age(49)作為二叉樹的頭結點,然后順序往下遍歷,把小于頭節點的age放到左邊,大于頭結點的age放到右邊,表中數據遍歷完以后就構造出了右圖所示的二叉樹索引結構。現在我們再來試著查找年齡為20的數據所需要的過程:
1.將age為20的數據先和頭結點的49比較(20<49),所以往左邊走
2.來到樹形結構的第二層,繼續和21比較(20<21),繼續往左邊走
3.來到樹形結構的第三層,和20比較(20=20)查,找成功
加上索引以后只需三次就查找成功了,可見索引確實可以提高我們SQL的查詢效率。
目前大部分數據庫系統及文件系統都采用B-Tree或其變種B+Tree作為索引結構,它的具體實現就在我們上面提到的引擎層的存儲引擎中。像上面提到的MyISAM存儲引擎就使用B-Tree來實現主鍵索引、唯一索引和非主鍵索引等。而InnoDB中的非主鍵索引使用的是B-Tree數據結構,主鍵索引則使用的是B+Tree。
那么B-Tree和B+Tree到底有什么區別呢?
B-Tree和B+Tree異同
B-Tree:它類似于像上面構建的普通二叉樹,但是B-樹允許每個節點有更多的子節點(二叉樹只允許有兩個),B-樹示意圖如下:
B-樹的特點:
(1)所有鍵值分布在整個樹中(B+Tree只分布在葉子節點中)
(2)任何關鍵字出現且只出現在一個節點中
(3)搜索有可能在非葉子節點結束
(4)在關鍵字全集內做一次查找,性能逼近二分查找算法
B+Tree:B+樹是B-樹的變體,B+樹的示意圖為: 從圖中也可以看到,B+樹與B樹的不同在于:
(1)所有關鍵字存儲在葉子節點,非葉子節點不存儲真正的data
(2)為所有葉子節點增加了一個鏈指針
B+樹相對于B樹在查詢上會更加優勝。
因為
什么場景不適合創建索引
- 在查詢中很少使用或者是參考的列不適合創建索引。因為既然這些列很少使用到,因此有無索引,并不能提高查詢速度。相反,增加了索引反而降低了系統的維護速度且增大了空間需求。
- 只有很少數據值的列不適合創建索引。因為本來結果集合就相當于全表查詢,因為由于這些列的取值很少,例如人事表的性別列,在查詢的結果中,結果集的數據行占了表中數據行的很大比例,即需要在表中搜索的數據行的比例很大。增加索引,并不能明顯加快檢索的速度。
- 被定義為text, image和bit數據類型的列不適合創建索引。因為這些列的數據量要么相當大,要么取值很少。
- 當修改性能遠遠大于檢索性能時不應該創建索引。修改性能和檢索性能是互相矛盾的。當增加索引時,會提高檢索性能,但會降低修改性能。當減少索引時,會提高修改性能,降低檢索性能。因此,當修改性能遠遠大于檢索性能時,不應該創建索引。
- 經常插入、刪除、修改的表
- 不會出現在where條件中的字段不適合建立索引。
什么樣的字段適合創建索引
1、表的主鍵、外鍵必須有索引;外鍵是唯一的,而且經常會用來查詢
2、數據量超過300的表應該有索引;
3、經常與其他表進行連接的表,在連接字段上應該建立索引;經常連接查詢,需要有索引
4、經常出現在Where子句中的字段,加快判斷速度,特別是大表的字段,應該建立索引,建立索引,一般用在select ……where f1 and f2 ,我們在f1或者f2上建立索引是沒用的。只有兩個使用聯合索引才能有用
5、經常用到排序的列上,因為索引已經排序。
6、經常用在范圍內搜索的列上創建索引,因為索引已經排序了,其指定的范圍是連續的
簡單記就是唯一、不為空、經常被查詢的字段
索引的分類
- 主鍵索引(PRIMAY KEY)
- 唯一索引(UNIQUE)
- 常規索引(INDEX)
- 全文索引(FULLTEXT)
1. 主鍵索引
主鍵:
某一個屬性組能唯一標識一條記錄
如:學生表(學號,姓名,班級,性別等等),學號時唯一標識的,可以作為主鍵。
特點:
最常見的索引類型
確保數據記錄的唯一性
確定特定數據記錄在數據庫中的位置
實例:
2. 唯一索引
作用:
避免同一個表中某數據列中的值重復
與主鍵索引的區別
主鍵索引只能有一個
唯一索引可有多個
實例:
CREATE TABLE `Grade`(`GradeID` INT(11) AUTO_INCREMENT PRIMARY KEY,`GradeName` VARCHAR(32) NOT NULL UNIQUE#或 UNIQUE KEY ` GradeID`(`GradeID`)3. 常規索引
作用:
快速定位特定數據
注意:
index 和 key 關鍵字都可以設置常規索引
應加在查詢條件的字段
不易添加太多常規索引,影響數據的插入,刪除和修改操作
實例:
4. 全文索引
作用:
快速定位特定數據
注意:
只能用于MyISAM類型的數據表
只能用于CHAR ,VARCHAR,TEXT數據列類型
使用大型數據集
實例:
唯一索引補充
它與前面的普通索引類似,不同的就是:索引列的值必須唯一,但允許有空值。如果是組合索引,則列值的組合必須唯一。它有以下幾種創建方式:
創建索引
修改表結構
ALTER table mytable ADD UNIQUE [indexName] (username(length))創建表的時候直接指定
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, UNIQUE [indexName] (username(length)) );基本索引
這是最基本的索引,它沒有任何限制。它有以下幾種創建方式:
如果是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;組合索引
為了形象地對比單列索引和組合索引,為表添加多個字段:
為了進一步榨取MySQL的效率,就要考慮建立組合索引。就是將 name, city, age建到一個索引里:
ALTER TABLE mytable ADD INDEX name_city_age (name(10),city,age);建表時,usernname長度為 16,這里用 10。這是因為一般情況下名字的長度不會超過10,這樣會加速索引查詢速度,還會減少索引文件的大小,提高INSERT的更新速度。
如果分別在 usernname,city,age上建立單列索引,讓該表有3個單列索引,查詢時和上述的組合索引效率也會大不一樣,遠遠低于我們的組合索引。雖然此時有了三個索引,但MySQL只能用到其中的那個它認為似乎是最有效率的單列索引。
建立這樣的組合索引,其實是相當于分別建立了下面三組組合索引
usernname,city,age usernname,city usernname 為什么沒有 city,age這樣的組合索引呢?這是因為MySQL組合索引“最左前綴”的結果。簡單的理解就是只從最左面的開始組合。并不是只要包含這三列的查詢都會用到該組合索引
下面的幾個SQL就會用到這個組合索引:
而下面幾個則不會用到
SELECT * FROM mytable WHREE age=20 AND city="株洲"SELECT * FROM mytable WHREE city="株洲"一般來說,在WHERE和JOIN中出現的列需要建立索引,但也不完全如此, 因為MySQL只對<,<=,=,>,>=,BETWEEN,IN,以及某些時候的LIKE才會使用索引。
例如:
SELECT t.Name FROM mytable t LEFT JOIN mytable m ON t.Name=m.username WHERE m.age=20 AND m.city=’株洲‘此時就需要對city和age建立索引,由于mytable表的userame也出現在了JOIN子句中,也有對它建立索引的必要。
剛才提到只有某些時候的LIKE才需建立索引。因為在以通配符%和_開頭作查詢時,MySQL不會使用索引。
例如下句會使用索引:
SELECT * FROM mytable WHERE username like’admin%’;而下句就不會使用:
SELECT * FROM mytable WHEREt Name like‘%admin’;因此,在使用LIKE時應注意以上的區別。
索引的不足
上面都在說使用索引的好處,但過多的使用索引將會造成濫用。因此索引也會有它的缺點:
雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對表進行INSERT、UPDATE和DELETE。因為更新表時,MySQL不僅要保存數據,還要保存一下索引文件。
建立索引會占用磁盤空間的索引文件。一般情況這個問題不太嚴重,但如果你在一個大表上創建了多種組合索引,索引文件會膨脹很快。
索引只是提高效率的一個因素,如果你的MySQL有大數據量的表,就需要花時間研究建立最優秀的索引,或優化查詢語句。
使用索引的細節問題
【須知】
使用索引時,有以下一些技巧和注意事項:
只要列中包含有NULL值都將不會被包含在索引中,復合索引中只要有一列含有NULL值,那么這一列對于此復合索引就是無效的。所以我們在數據庫設計時不要讓字段的默認值為NULL。
對串列進行索引,如果可能應該指定一個前綴長度。例如,如果有一個CHAR(255)的列,如果在前10個或20個字符內,多數值是惟一的,那么就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節省磁盤空間和I/O操作。
MySQL查詢只使用一個索引,因此如果where子句中已經使用了索引的話,那么order by中的列是不會使用索引的。因此數據庫默認排序可以符合要求的情況下不要使用排序操作;盡量不要包含多個列的排序,如果需要最好給這些列創建復合索引。
一般情況下不鼓勵使用like操作,如果非使用不可,如何使用也是一個問題。like “%aaa%” 不會使用索引而like “aaa%”可以使用索引。
因為邏輯判斷會讓索引失效。例如
可以這樣查詢:
select id from t where num=10 union all select id from t where num=20上面提到數據庫引擎,如果不清楚的童鞋可以看看這篇?MySQL兩種存儲引擎
推薦閱讀?B-Tree和B+樹詳解
本篇參考90%的程序員不懂數據庫的索引知識,看完之后你就懂了
mysql索引的新手入門詳解
總結
- 上一篇: Android应用程序访问linux驱动
- 下一篇: Hybrid App基础知识