⑴ mysql 聯合索引原理詳述
在一個市民信息表上,是否有必要將身份證號
和名字建立聯合索引?
假設這個市民表的定義是這樣的:
CREATE TABLE `tuser` (
`id` int(11) NOT NULL,
`id_card` varchar(32) DEFAULT NULL,
`name` varchar(32) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`ismale` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `id_card` (`id_card`),
KEY `name_age` (`name`,`age`)
) ENGINE=InnoDB
我們知道,身份證號是市民的唯一標識。也就是說,如果有根據身份證號查詢市民信息的需求,
我們只要在身份證號欄位上建立索引就夠了。而再建立一個(身份證號、姓名)的聯合索引,是
不是浪費空間?
如果現在有一個高頻請求,要根據市民的身份證號查詢他的姓名,這個聯合索引就有意義了。它
可以在這個高頻請求上用到覆蓋索引,不再需要回表查整行記錄,減少語句的執行時間。
當然,索引欄位的維護總是有代價的。因此,在建立冗餘索引來支持覆蓋索引時就需要權衡考慮
了。這正是業務 DBA,或者稱為業務數據架構師的工作。
最左前綴原則
看到這里你一定有一個疑問,如果為每一種查詢都設計一個索引,索引是不是太多了。如果我現
在要按照市民的身份證號去查他的家庭地址呢?雖然這個查詢需求在業務中出現的概率不高,但
總不能讓它走全表掃描吧?反過來說,單獨為一個不頻繁的請求創建一個(身份證號,地址)的
索引又感覺有點浪費。應該怎麼做呢?
這里,我先和你說結論吧。B+ 樹這種索引結構,可以利用索引的「最左前綴」,來定位記錄。
為了直觀地說明這個概念,我們用(name,age)這個聯合索引來分析。
圖 2 (name,age)索引示意圖
可以看到,索引項是按照索引定義里面出現的欄位順序排序的。
當你的邏輯需求是查到所有名字是「張三」的人時,可以快速定位到 ID4,然後向後遍歷得到所有
需要的結果。
如果你要查的是所有名字第一個字是「張」的人,你的 SQL 語句的條件是"where name like 『張
%』"。這時,你也能夠用上這個索引,查找到第一個符合條件的記錄是 ID3,然後向後遍歷,直
到不滿足條件為止。
可以看到,不只是索引的全部定義,只要滿足最左前綴,就可以利用索引來加速檢索。這個最左
前綴可以是聯合索引的最左 N 個欄位,也可以是字元串索引的最左 M 個字元。
基於上面對最左前綴索引的說明,我們來討論一個問題:在建立聯合索引的時候,如何安排索引
內的欄位順序。
這里我們的評估標準是,索引的復用能力。因為可以支持最左前綴,所以當已經有了 (a,b) 這個
聯合索引後,一般就不需要單獨在 a 上建立索引了。因此,第一原則是,如果通過調整順序,可
以少維護一個索引,那麼這個順序往往就是需要優先考慮採用的。
所以現在你知道了,這段開頭的問題里,我們要為高頻請求創建 (身份證號,姓名)這個聯合索
引,並用這個索引支持「根據身份證號查詢地址」的需求。
那麼,如果既有聯合查詢,又有基於 a、b 各自的查詢呢?查詢條件里面只有 b 的語句,是無法
使用 (a,b) 這個聯合索引的,這時候你不得不維護另外一個索引,也就是說你需要同時維護
(a,b)、(b) 這兩個索引。
這時候,我們要考慮的原則就是空間了。比如上面這個市民表的情況,name 欄位是比 age 欄位
大的 ,那我就建議你創建一個(name,age) 的聯合索引和一個 (age) 的單欄位索引。
⑵ 資料庫的索引是如何實現的,主鍵索引和聯合索引數據結構有什麼區別
主鍵是表中的一個或多個欄位,它的值用於惟一地標識表中的某一條記錄.且不能為空;
索引是對資料庫表中一列或多列的值進行排序的一種結構,只有當經常查詢索引列中的數據時,才需要在表上創建索引,使用索引可快速訪問資料庫表中的特定信息。
索引佔用磁碟空間,並且降低添加、刪除和更新行的速度。當然索引也有好處就是查詢速度快,它利還是大於弊的所以請慎重使用索引。
比如:一個學生表(t_stu
)有1000條數據,給它id列建個主鍵和索引,
你想查詢id=1000;的這條信息,如果沒有索引,它就一條一條的比對查找,系統運行1000次才找到,要是創建了索引,你查詢id=1000的這條信息,系統只運行一次就找到了。
⑶ 資料庫聯合索引abc,只查詢ac可以嗎
這樣的,你建立的是聯合索引,而是看你的查詢條件經常用到哪幾列,
如果經常同時用到好幾列,就可以在這幾列上建聯合索引,
如果查詢條件經常都只是用到某一個欄位,按照索引中欄位順序使用才會最大化的發揮索引的作用。
⑷ 聯合索引和唯一索引的區別是什麼當使用聯合索引中的一個欄位查詢時會不會用到索引
聯合索引是由多個欄位組成的索引。
唯一索引是使用索引可快速訪問資料庫表中的特定信息。
查詢時使用聯合索引的一個欄位,如果這個欄位在聯合索引中所有欄位的第一個,那就會用到索引,否則就無法使用到索引。
⑸ 深入理解mysql的聯合索引
最近在學習MySQL的存儲引擎和索引的知識。看了許多篇介紹MyISAM和InnoDB的索引的例子,都能理解。
像這張索引圖:
PS:該圖來自大神張洋的《MySQL索引背後的數據結構及演算法原理》一文。
但許多文章講述的都是單列索引,我很好奇 聯合索引對應的結構圖是怎樣的。
比方說聯合索引 (col1, col2,col3),我知道在邏輯上是先按照col1進行排序再按照col2進行排序最後再按照col3進行排序。因此如果是select * from table where col1 = 1 and col3 = 3的話,只有col1的索引部分能生效。但是其物理結構上這個聯合索引是怎樣存在的,我想不懂。
上網查閱了許多資料,總算有點眉目了。
假設這是一個多列索引(col1, col2,col3),對於葉子節點,是這樣的:
PS:該圖改自《MySQL索引背後的數據結構及演算法原理》一文的配圖。
也就是說,聯合索引(col1, col2,col3)也是一棵B+Tree,其非葉子節點存儲的是第一個關鍵字的索引,而葉節點存儲的則是三個關鍵字col1、col2、col3三個關鍵字的數據,且按照col1、col2、col3的順序進行排序。
配圖可能不太讓人滿意,因為col1都是不同的,也就是說在col1就已經能確定結果了。自己又畫了一個圖(有點丑),col1表示的是年齡,col2表示的是姓氏,col3表示的是名字。如下圖:
PS:對應地址指的是數據記錄的地址。
如圖,聯合索引(年齡, 姓氏,名字),葉節點上data域存儲的是三個關鍵字的數據。且是按照年齡、姓氏、名字的順序排列的。
因此,如果執行的是:
select * from STUDENT where 姓氏='李' and 名字='安'
或者
select * from STUDENT where 名字='安'
那麼當執行查詢的時候,是無法使用這個聯合索引的。因為聯合索引中是先根據年齡進行排序的。如果年齡沒有先確定,直接對姓氏和名字進行查詢的話,就相當於亂序查詢一樣,因此索引無法生效。因此查詢是全表查詢。
如果執行的是:
select * from STUDENT where 年齡=1 and 姓氏='李'
那麼當執行查詢的時候,索引是能生效的,從圖中很直觀的看出,age=1的是第一個葉子節點的前6條記錄,在age=1的前提下,姓氏=』李』的是前3條。因此最終查詢出來的是這三條,從而能獲取到對應記錄的地址。
如果執行的是:
select * from STUDENT where 年齡=1 and 姓氏='黃' and 名字='安'
那麼索引也是生效的。
而如果執行的是:
select * from STUDENT where 年齡=1 and 名字='安'
那麼,索引年齡部分能生效,名字部分不能生效。也就是說索引部分生效。
因此我對聯合索引結構的理解就是B+Tree是按照第一個關鍵字進行索引,然後在葉子節點上按照第一個關鍵字、第二個關鍵字、第三個關鍵字…進行排序。
而之所以會有最左原則,是因為聯合索引的B+Tree是按照第一個關鍵字進行索引排列的。
聯合索引在B+樹上的結構介紹
⑹ 什麼是mysql的聯合索引,怎麼建立mysql的索引。
聯合索引是由多個欄位組成的索引。
CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name
[USING index_type]
ON tbl_name (index_col_name,...)
index_col_name:
col_name [(length)] [ASC | DESC]
如果你經常要用到多個欄位的多條件查詢,可以考慮建立聯合索引,一般是除第一個欄位外的其它欄位不經常用於條件篩選情況,比如說a,b 兩個欄位,如果你經常用a條件或者a+b條件去查詢,而很少單獨用b條件查詢,那麼可以建立a,b的聯合索引。如果a和b都要分別經常獨立的被用作查詢條件,那還是建立多個單列索引。