目錄
- 回表
- 覆蓋索引
- 最左前綴原則
- 聯合索引的時候,如何安排索引內的字段順序?
- 索引下推
- 重建索引問題
- 聯合主鍵索引和 InnoDB 索引組織表問題
- in與between的區別
回表
回到主鍵索引樹搜索的過程,我們稱為回表。
覆蓋索引
覆蓋索引就是在這次的查詢中,所要的數據已經在這棵索引樹的葉子結點上了。
select ID from T where k between 3 and 5
ID 的值已經在 k 索引樹上了,因此可以直接提供查詢結果,不需要回表.
由于覆蓋索引可以減少樹的搜索次數,顯著提升查詢性能,所以使用覆蓋索引是一個常用的性能優化手段。
覆蓋索引的第二個使用:在聯合索引上使用,也可以避免回表。
如果現在有一個高頻請求,要根據市民的身份證號查詢他的姓名。我們可以建立一個(身份證號、姓名)的聯合索引。它可以在這個高頻請求上用到覆蓋索引,不再需要回表查整行記錄,減少語句的執行時間。
最左前綴原則
聯合索引先根據第一個字段排序,如果第一個字段有相同的,就按照第二個字段排序。
只要滿足最左前綴,就可以利用索引來加速檢索。這個最左前綴可以是聯合索引的最左 N 個字段,也可以是字符串索引的最左 M 個字符。
聯合索引的時候,如何安排索引內的字段順序?
第一原則:
如果通過調整順序,可以少維護一個索引,那么這個順序往往就是需要優先考慮采用的。
如果我們有個頻繁的要求:根據姓名找到該人身份證,那么應該建立聯合索引:(name,ID)
反之,如果我們有個頻繁的要求:根據該人身份證找到該人姓名,那么應該建立聯合索引:(ID,name)
索引下推
索引覆蓋是你要查的信息在二級索引中已經有了,就不需要回表。索引下推是你的過濾條件有一部分符合了最左前綴,那么會用上索引,如果此時不符合最左前綴的部分剛好有聯合索引中的字段,那么在利用最左前綴進行索引查詢的同時,會根據這些字段多做一步過濾,減少索引查詢出來的條數,這樣就減少了回表次數。
如:
mysql> select * from tuser where name like '張%' and age=10 and ismale=1;
![]() | ![]() |
重建索引問題
假設,我們有一個主鍵列為 ID 的表,表中有字段 k,并且在 k 上有索引。
mysql> create table T(
id int primary key,
k int not null,
name varchar(16),
index (k))engine=InnoDB;
如果你要重建索引 k:
alter table T drop index k;
alter table T add index(k);
如果你要重建主鍵索引:
alter table T drop primary key;
alter table T add primary key(id);
上面這兩個重建索引的作法對此有什么理解?
為什么要重建索引?
索引可能因為刪除,或者頁分裂等原因,導致數據頁有空洞,重建索引的過程會創建一個新的索引,把數據按順序插入,這樣頁面的利用率最高,也就是索引更緊湊、更省空間。
理解
不論是刪除主鍵還是創建主鍵,都會將整個表重建。所以連著執行這兩個語句的話,第一個語句就白做了。
推薦使用:
alter table T engine=InnoDB
聯合主鍵索引和 InnoDB 索引組織表問題
有這么一個表:
CREATE TABLE `geek` (`a` int(11) NOT NULL,`b` int(11) NOT NULL,`c` int(11) NOT NULL,`d` int(11) NOT NULL,PRIMARY KEY (`a`,`b`),KEY `c` (`c`),KEY `ca` (`c`,`a`),KEY `cb` (`c`,`b`)
) ENGINE=InnoDB;
既然主鍵包含了 a、b 這兩個字段,那意味著單獨在字段 c 上創建一個索引,就已經包含了三個字段了呀,為什么要創建“ca”“cb”這兩個索引?同事告訴他,是因為他們的業務里面有這樣的兩種語句:
select * from geek where c=N order by a limit 1;
select * from geek where c=N order by b limit 1;
為了這兩個查詢模式,這兩個索引是否都是必須的?為什么呢?
表記錄:
主鍵 a,b 的聚簇索引組織順序相當于 order by a,b ,也就是先按 a 排序,再按 b 排序,c 無序。
a | b | c | d |
---|---|---|---|
1 | 2 | 3 | d |
1 | 3 | 2 | d |
1 | 4 | 3 | d |
2 | 1 | 3 | d |
2 | 2 | 2 | d |
2 | 3 | 4 | d |
索引 ca 的組織是先按 c 排序,再按 a 排序,同時記錄主鍵:
這個跟索引 c 的數據是一模一樣的。
c | a | b |
---|---|---|
2 | 1 | 3 |
2 | 2 | 2 |
3 | 1 | 2 |
3 | 1 | 4 |
3 | 2 | 1 |
4 | 2 | 3 |
索引 cb 的組織是先按 c 排序,再按 b 排序,同時記錄主鍵:
c | b | a |
---|---|---|
2 | 2 | 2 |
2 | 3 | 1 |
3 | 1 | 2 |
3 | 2 | 1 |
3 | 4 | 1 |
4 | 3 | 2 |
所以,結論是 ca 可以去掉,cb 需要保留。
in與between的區別
--1.
select * from T where k in(1,2,3,4,5)
--2.
select * from T where k between 1 and 5
1.in 內部的數字是未知的,不知道是否有序,是否連續等,所以你只能一個一個去看。
2.一個已知的升序、范圍查詢,只需定位第一個值,后面遍歷就行了。