如何理解Mysql的索引及他們的原理?
面試官:我看你簡歷上寫了MySQL,對MySQL InnoDB引擎的索引了解嗎?
候選者:嗯啊,使用索引可以加快查詢速度,其實上就是將無序的數(shù)據(jù)變成有序(有序就能加快檢索速度)
候選者:在InnoDB引擎中,索引的底層數(shù)據(jù)結(jié)構(gòu)是B+樹
面試官:那為什么不使用紅黑樹或者B樹呢?
候選者:MySQL的數(shù)據(jù)是存儲在硬盤的,在查詢時一般是不能「一次性」把全部數(shù)據(jù)加載到內(nèi)存中
候選者:紅黑樹是「二叉查找樹」的變種,一個Node節(jié)點只能存儲一個Key和一個Value
候選者:B和B+樹跟紅黑樹不一樣,它們算是「多路搜索樹」,相較于「二叉搜索樹」而言,一個Node節(jié)點可以存儲的信息會更多,「多路搜索樹」的高度會比「二叉搜索樹」更低。
候選者:了解了區(qū)別之后,其實就很容易發(fā)現(xiàn),在數(shù)據(jù)不能一次加載至內(nèi)存的場景下,數(shù)據(jù)需要被檢索出來,選擇B或B+樹的理由就很充分了(一個Node節(jié)點存儲信息更多(相較于二叉搜索樹),樹的高度更低,樹的高度影響檢索的速度)
候選者:B+樹相對于B樹而言,它又有兩種特性。
候選者:一、B+樹非葉子節(jié)點不存儲數(shù)據(jù),在相同的數(shù)據(jù)量下,B+樹更加矮壯。(這個應(yīng)該不用多解釋了,數(shù)據(jù)都存儲在葉子節(jié)點上,非葉子節(jié)點的存儲能存儲更多的索引,所以整棵樹就更加矮壯)
候選者:二、B+樹葉子節(jié)點之間組成一個鏈表,方便于遍歷查詢(遍歷操作在MySQL中比較常見)

候選者:我稍微解釋一下吧,你可以腦補下畫面
候選者:我們在MySQL InnoDB引擎下,每創(chuàng)建一個索引,相當于生成了一顆B+樹。
候選者:如果該索引是「聚集(聚簇)索引」,那當前B+樹的葉子節(jié)點存儲著「主鍵和當前行的數(shù)據(jù)」
候選者:如果該索引是「非聚簇索引」,那當前B+樹的葉子節(jié)點存儲著「主鍵和當前索引列值」
候選者:比如寫了一句sql:select * from user where id >=10,那只要定位到id為10的記錄,然后在葉子節(jié)點之間通過遍歷鏈表(葉子節(jié)點組成的鏈表),即可找到往后的記錄了。
候選者:由于B樹是會在非葉子節(jié)點也存儲數(shù)據(jù),要遍歷的時候可能就得跨層檢索,相對麻煩些。
候選者:基于樹的層級以及業(yè)務(wù)使用場景的特性,所以MySQL選擇了B+樹作為索引的底層數(shù)據(jù)結(jié)構(gòu)。
候選者:對于哈希結(jié)構(gòu),其實InnoDB引擎是「自適應(yīng)」哈希索引的(hash索引的創(chuàng)建由InnoDB存儲引擎引擎自動優(yōu)化創(chuàng)建,我們是干預(yù)不了)
面試官:嗯…那我了解了,順便想問下,你知道什么叫做回表嗎?
候選者:所謂的回表其實就是,當我們使用索引查詢數(shù)據(jù)時,檢索出來的數(shù)據(jù)可能包含其他列,但走的索引樹葉子節(jié)點只能查到當前列值以及主鍵ID,所以需要根據(jù)主鍵ID再去查一遍數(shù)據(jù),得到SQL 所需的列
候選者:舉個例子,我這邊建了給訂單號ID建了個索引,但我的SQL 是:select orderId,orderName from orderdetail where orderId = 123
候選者:SQL都訂單ID索引,但在訂單ID的索引樹
的葉子節(jié)點只有orderId和Id,而我們還想檢索出orderName,所以MySQL 會拿到ID再去查出orderName給我們返回,這種操作就叫回表

候選者:想要避免回表,也可以使用覆蓋索引(能使用就使用,因為避免了回表操作)。
候選者:所謂的覆蓋索引,實際上就是你想要查出的列剛好在葉子節(jié)點上都存在,比如我建了orderId和orderName聯(lián)合索引,剛好我需要查詢也是orderId和orderName,這些數(shù)據(jù)都存在索引樹的葉子節(jié)點上,就不需要回表操作了。
面試官:既然你也提到了聯(lián)合索引,我想問下你了解最左匹配原則嗎?
候選者:嗯,說明這個概念,還是舉例子比較容易說明
候選者:如有索引 (a,b,c,d),查詢條件 a=1 and b=2 and c>3 and d=4,則會在每個節(jié)點依次命中a、b、c,無法命中d
候選者:先匹配最左邊的,索引只能用于查找key是否存在(相等),遇到范圍查詢 (>、<、between、like左匹配)等就不能進一步匹配了,后續(xù)退化為線性查找
候選者:這就是最左匹配原則

面試官:嗯嗯,我還想問下你們主鍵是怎么生成的?
候選者:主鍵就自增的
面試官:那假設(shè)我不用MySQL自增的主鍵,你覺得會有什么問題呢?
候選者:首先主鍵得保證它的唯一性和空間盡可能短吧,這兩塊是需要考慮的。
候選者:另外,由于索引的特性(有序),如果生成像uuid

本文總結(jié):
為什么B+樹?數(shù)據(jù)無法一次load到內(nèi)存,B+樹是多路搜索樹,只有葉子節(jié)點才存儲數(shù)據(jù),葉子節(jié)點之間鏈表進行關(guān)聯(lián)。(樹矮,易遍歷)
什么是回表?非聚簇索引在葉子節(jié)點只存儲列值以及主鍵ID,有條件下盡可能用覆蓋索引避免回表操作,提高查詢速度
什么是最左匹配原則?從最左邊為起點開始連續(xù)匹配,遇到范圍查詢終止
主鍵非自增會有什么問題?插入效率下降,存在移動塊的數(shù)據(jù)問題