如果格式饿这、圖片有問題,歡迎查看原文(可能會有更新撞秋、也歡迎交流):《數(shù)據(jù)庫上多列索引是否可以使用其查詢單一列长捧?》
今天被問到一個關于數(shù)據(jù)庫索引(index)的問題,一下子被問住了吻贿。于是網(wǎng)上找了資料整理學習了下串结。問題如下:
如果在一個表中的A和B上建立了聯(lián)合索引(多列索引),那么如果我查詢B列的時候舅列,是否會使用這個索引肌割。
答案在整理知識點之后就很簡單了。
什么是索引帐要?
索引是存儲的表中一個特定列的值數(shù)據(jù)結構把敞,一般是B-Tree,還有HashTable Index和R-Tree榨惠,我們這里只討論B-Tree奋早。索引是在表的列上創(chuàng)建盛霎,索引只包含包含一個表中列的值,并且這些值存儲在一個數(shù)據(jù)結構中耽装。索引是一種數(shù)據(jù)結構 愤炸。
當我們查詢沒有索引的列的時候,需要對比所有記錄掉奄,而索引已經(jīng)排序规个,所以查詢的時候可以快速找到所有對應的值。比如我們在姓名中尋找“Chris”姓建,沒有索引的情況下绰姻,需要核對整個列表的數(shù)據(jù),以免最最后一列有chris引瀑,但是有索引之后狂芋,因為已經(jīng)排序,所以所有chris都在一起憨栽,所以非常高效帜矾。
索引存儲了指向表中某一行的指針
如果我們在索引里找到某一條記錄作為索引的列的值,如何才能找到這一條記錄的其它值呢屑柔?這是很簡單 – 數(shù)據(jù)庫索引同時存儲了指向表中的相應行的指針屡萤。指針是指一塊內(nèi)存區(qū)域, 該內(nèi)存區(qū)域記錄的是對硬盤上記錄的相應行的數(shù)據(jù)的引用掸宛。因此死陆,索引中除了存儲列的值,還存儲著一個指向在行數(shù)據(jù)的索引唧瘾。
數(shù)據(jù)庫怎么知道什么時候使用索引措译?
SELECT * FROM Employee WHERE Employee_Name = ‘Chris’
當這個SQL 運行時,數(shù)據(jù)庫會檢查在查詢的列上是否有索引饰序。假設Employee_Name列上確實創(chuàng)建了索引领虹,數(shù)據(jù)庫會接著檢查使用這個索引做查詢是否合理 – 因為有些場景下,使用索引比起全表掃描會更加低效求豫。如何合理就使用索引塌衰。
如何創(chuàng)建索引
CREATE INDEX name_index
ON Employee (Employee_Name)
如果是聯(lián)合索引(多列索引)
CREATE INDEX name_index
ON Employee (Employee_Name, Employee_Age)
索引的代價?
那么蝠嘉,使用數(shù)據(jù)庫索引有什么缺點呢靶庙?其一翅楼,索引會占用空間 – 你的表越大泣矛,索引占用的空間越大矗漾。其二,性能損失(主要值更新操作)罩缴,當你在表中添加蚊逢、刪除或者更新行數(shù)據(jù)的時候层扶, 在索引中也會有相同的操作。
單列索引VS多列索引
假設我們要在用戶表分別查詢firstname烙荷、lastname镜会、age,我們?nèi)绾谓⑺饕兀?/p>
Select id?
FROM people?
Where firstname='Mike'?
? ? ? AND lastname='Sullivan' AND age=17;
我們可以考慮在單個列上創(chuàng)建索引终抽,比如firstname戳表、lastname或者age列。如果我們創(chuàng)建firstname列的索引昼伴,MySQL將通過這個索引迅速把搜索范圍限制到那些firstname=’Mike’的記錄匾旭,然后再在這個“中間結果集”上進行他條件的搜索:它首先排除那些lastname不等于“Sullivan”的記錄,然后排除那些age不等于17的記錄圃郊。當記錄滿足所有搜索條件之后价涝,MySQL就返回最終的搜索結果。
由于建立了firstname列的索引持舆,與執(zhí)行表的完全掃描相比色瘩,MySQL的效率提高了很多,但我們要求MySQL掃描的記錄數(shù)量仍舊遠遠超過了實際所需要的逸寓。雖然我們可以刪除firstname列上的索引居兆,再創(chuàng)建lastname或者age列的索引,但總地看來竹伸,不論在哪個列上創(chuàng)建索引搜索效率仍舊相似泥栖。
這時候我們要建立firstname、lastname勋篓、age的多列索引吧享。
如果在firstname、lastname生巡、age這三個列上分別創(chuàng)建單列索引耙蔑,效果是否和創(chuàng)建一個firstname、lastname孤荣、age的多列索引一樣呢?
答案是否定的须揣,兩者完全不同盐股。當我們執(zhí)行查詢的時候,MySQL只能使用一個索引耻卡。如果你有三個單列的索引疯汁,MySQL會試圖選擇一個限制最嚴格的索引。但是卵酪,即使是限制最嚴格的單列索引幌蚊,它的限制能力也肯定遠遠低于firstname谤碳、lastname、age這三個列上的多列索引溢豆。
多列索引中最左前綴
多列索引還有另外一個優(yōu)點蜒简,它通過稱為最左前綴(Leftmost Prefixing)的概念體現(xiàn)出來。繼續(xù)考慮前面的例子漩仙,現(xiàn)在我們有一個firstname搓茬、lastname、age列上的多列索引队他,我們稱這個索引為fname_lname_age卷仑。當搜索條件是以下各種列的組合時,MySQL將使用fname_lname_age索引:
firstname麸折,lastname锡凝,age
firstname,lastname
firstname
也就是垢啼,它相當于我們創(chuàng)建了(firstname私爷,lastname,age)膊夹、(firstname衬浑,lastname)以及(firstname)這些列組合上的索引。
所以答案有了吧放刨!