在一個市民信息表上狂魔,是否有必要將身份證號
和名字建立聯(lián)合索引慈迈?
假設這個市民表的定義是這樣的:
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
我們知道,身份證號是市民的唯一標識仰猖。也就是說皿伺,如果有根據(jù)身份證號查詢市民信息的需求,
我們只要在身份證號字段上建立索引就夠了撞鹉。而再建立一個(身份證號、姓名)的聯(lián)合索引颖侄,是
不是浪費空間鸟雏?
如果現(xiàn)在有一個高頻請求,要根據(jù)市民的身份證號查詢他的姓名览祖,這個聯(lián)合索引就有意義了孝鹊。它
可以在這個高頻請求上用到覆蓋索引,不再需要回表查整行記錄展蒂,減少語句的執(zhí)行時間又活。
當然,索引字段的維護總是有代價的锰悼。因此柳骄,在建立冗余索引來支持覆蓋索引時就需要權(quán)衡考慮
了。這正是業(yè)務 DBA箕般,或者稱為業(yè)務數(shù)據(jù)架構(gòu)師的工作耐薯。
最左前綴原則
看到這里你一定有一個疑問,如果為每一種查詢都設計一個索引,索引是不是太多了曲初。如果我現(xiàn)
在要按照市民的身份證號去查他的家庭地址呢体谒?雖然這個查詢需求在業(yè)務中出現(xiàn)的概率不高,但
總不能讓它走全表掃描吧臼婆?反過來說抒痒,單獨為一個不頻繁的請求創(chuàng)建一個(身份證號,地址)的
索引又感覺有點浪費颁褂。應該怎么做呢评汰?
這里,我先和你說結(jié)論吧痢虹。B+ 樹這種索引結(jié)構(gòu),可以利用索引的“最左前綴”主儡,來定位記錄奖唯。
為了直觀地說明這個概念,我們用(name糜值,age)這個聯(lián)合索引來分析丰捷。
? ? ? ? ? ? ? ? ? ? ?圖 2 (name,age)索引示意圖
可以看到寂汇,索引項是按照索引定義里面出現(xiàn)的字段順序排序的病往。
當你的邏輯需求是查到所有名字是“張三”的人時,可以快速定位到 ID4骄瓣,然后向后遍歷得到所有
需要的結(jié)果停巷。
如果你要查的是所有名字第一個字是“張”的人,你的 SQL 語句的條件是"where name like ‘張
%’"榕栏。這時畔勤,你也能夠用上這個索引,查找到第一個符合條件的記錄是 ID3扒磁,然后向后遍歷庆揪,直
到不滿足條件為止。
可以看到妨托,不只是索引的全部定義缸榛,只要滿足最左前綴,就可以利用索引來加速檢索兰伤。這個最左
前綴可以是聯(lián)合索引的最左 N 個字段内颗,也可以是字符串索引的最左 M 個字符。
基于上面對最左前綴索引的說明医清,我們來討論一個問題:在建立聯(lián)合索引的時候起暮,如何安排索引
內(nèi)的字段順序。
這里我們的評估標準是,索引的復用能力负懦。因為可以支持最左前綴筒捺,所以當已經(jīng)有了 (a,b) 這個
聯(lián)合索引后,一般就不需要單獨在 a 上建立索引了纸厉。因此系吭,第一原則是,如果通過調(diào)整順序颗品,可
以少維護一個索引肯尺,那么這個順序往往就是需要優(yōu)先考慮采用的。
所以現(xiàn)在你知道了躯枢,這段開頭的問題里则吟,我們要為高頻請求創(chuàng)建 (身份證號,姓名)這個聯(lián)合索
引锄蹂,并用這個索引支持“根據(jù)身份證號查詢地址”的需求氓仲。
那么,如果既有聯(lián)合查詢得糜,又有基于 a敬扛、b 各自的查詢呢?查詢條件里面只有 b 的語句朝抖,是無法
使用 (a,b) 這個聯(lián)合索引的啥箭,這時候你不得不維護另外一個索引,也就是說你需要同時維護
(a,b)治宣、(b) 這兩個索引急侥。
這時候,我們要考慮的原則就是空間了炼七。比如上面這個市民表的情況缆巧,name 字段是比 age 字段
大的 ,那我就建議你創(chuàng)建一個(name,age) 的聯(lián)合索引和一個 (age) 的單字段索引豌拙。