一、 爲什麼加索引
-
主要原因:可以利用二分查找大大加快數據的檢索速度(B+樹)
-
通過創建唯一性索引,可以保證數據庫表中每一行數據的唯一性
-
可以加速表和表之間的連接
二、 如何加索引
1. 場景介紹
引入一個場景,以下面的表爲例,這個表有5個字段,分別是id,name,time,subject和grade,我們要進行如下兩種操作
- 查詢某一個人某一門科目在某一天考了多少分
- 查詢某一個人某一門科目在某個時間範圍內分別考了多少分
字段名 | 字段含義 |
---|---|
id | 主鍵id |
name | 姓名 |
time | 時間 |
subject | 科目 |
grade | 成績 |
假設數據如下
id | name | time | subject | grade |
---|---|---|---|---|
1 | Bob | 3 | English | 95 |
2 | Jack | 3 | English | 98 |
3 | Jack | 3 | Math | 97 |
4 | Bob | 6 | English | 90 |
5 | Bob | 8 | English | 93 |
6 | Bob | 7 | Math | 100 |
假設我們現在需要查詢Bob在第3天英語考了幾分,由於存儲結構亂序的,所以數據庫內部只能一個個遍歷然後比較name,subject和time是否滿足條件,其複雜度爲O(n),非常低效
select * from test_index
where name = 'Bob'
and time = 3
and subject = 'English';
2. 加入索引
給數據表加索引其實就是給某個字段建立了一個排序表,相當於圖書館裏給每本書進行編號,並按照順序放在書架上,我們要想找到指定編號的圖書時,只需要使用類似二分查找的方式,就可以快速找到對應的圖書了。
二分查找時間複雜度爲O(logn),當n爲109時,大約只要執行30次對比,所以相比於O(n)的複雜度高效不少
加了索引之後,數據庫會分配一個額外的空間,用來存儲索引表,每次對數據庫進行插入、刪除和修改的時候也會修改索引表,所以增加索引之後,會增加數據庫的大小和以及數據庫修改的時間。因此如果數據庫修改多而查詢少,就要考慮增加索引的性價比。
舉個例子,我們對上面的表中的name字段增加索引
ALTER TABLE `normandb`.`test_index`
ADD INDEX `index`(`name`) USING BTREE
然後索引表就會變成如下般呈現
name | id | time | subject | grade |
---|---|---|---|---|
Bob | 1 | 3 | English | 95 |
Bob | 4 | 6 | English | 90 |
Bob | 5 | 8 | English | 93 |
Bob | 6 | 7 | Math | 100 |
Jack | 2 | 3 | English | 98 |
Jack | 3 | 3 | Math | 97 |
可以看到,索引表按照name進行了排序,這樣的話,如果我們要按照name去進行查詢的時候,能很快地在索引表裏找到符合要求的name。
顯而易見,之前我們的查詢,需要給name,time和subject都加上索引,那是不是直接給這三個字段都加上索引就行了呢?
ALTER TABLE `normandb`.`test_index`
ADD INDEX `index`(`name`) USING BTREE,
ADD INDEX `index2`(`time`) USING BTREE,
ADD INDEX `index3`(`subject`) USING BTREE
冷靜分析,這其實是不可以的,如果爲每一個字段各自建一個索引,那就會建立三個依照各自字段進行排序的索引表,當我們使用完name索引之後拿到的數據在time索引表中是亂序的,所以就無法二分查找了。
所以就要用到組合索引。
3. 組合索引
ALTER TABLE `normandb`.`test_index`
ADD UNIQUE INDEX `index`(`name`, `time`, `subject`) USING BTREE;
用上面語句我們就可以建立一個基於name,time,subject三個字段的索引,數據庫就會按照創建時的順序,對各個字段進行排序建立索引表,如下所示
name | time | subject | grade |
---|---|---|---|
Bob | 3 | English | 95 |
Bob | 6 | English | 90 |
Bob | 7 | Math | 100 |
Bob | 8 | English | 93 |
Jack | 3 | English | 98 |
Jack | 3 | Math | 97 |
這樣的話,去查找我們需要的信息,只需要進行三次二分查找就行了,時間複雜度爲O(k*logn)
PS : 可以注意到上面建立索引的時候用了UNIQUE INDEX,這個其實就是唯一索引,確定了唯一索引之後,數據表中這三個字段一模一樣的數據只能出現一次,之後插入會執行失敗,可以保證唯一性
4. 範圍查詢
如果我們想要知道Bob在第5天到第8天的英語成績分別是多少,數據庫語句應該是這樣
select * from test_index
where name = 'Bob'
and time >= 5 and time <= 8
and subject = 'English';
這時候我們回去看看上面建立的組合索引,就會發現對time進行排序之後,篩選出的數據subject字段是亂序的,那麼查詢效率就又下降了不少了,因爲subject字段相當於要在time字段相等的情況下才會保持有序。
所以增加索引的語句應該是這樣
ALTER TABLE `normandb`.`test_index`
ADD UNIQUE INDEX `index`(`name`, `subject`, `time`) USING BTREE;
三、 總結
- 使用索引能夠加快查詢速度
- 經常作爲查詢條件的字段可以設置索引
- 設置索引會降低修改數據時的效率,不是越多越好
- 在建立索引的時候:等值查詢的字段,儘量放在範圍查詢的字段前面