Mysql索引不會怎么辦滑进?6000字長文教會你

MySQL的索引入門真的很難嗎

經(jīng)常在開發(fā)中碰到同事說募谎,數(shù)據(jù)查詢好慢扶关,第一個反應(yīng)就是給表加個索引。從而引發(fā)想去探索下我們常說的索引究竟是什么数冬?難道只需要加個索引就能解決數(shù)據(jù)庫查詢問題嗎节槐?

帶著這個問題我們開始探究MySQL中的索引究竟是什么,它能幫助我們做些什么吉执。

腦圖

索引存在的意義

在現(xiàn)有程序業(yè)務(wù)中疯淫,數(shù)據(jù)庫作為存儲的重要一環(huán),不可或缺戳玫,而對于數(shù)據(jù)庫的操作無外乎是增刪改查,但隨著數(shù)據(jù)量的增加未斑,數(shù)據(jù)庫的性能就成為最重要的一環(huán)咕宿,數(shù)據(jù)查詢不能慢,數(shù)據(jù)查詢一慢,用戶體驗(yàn)就會差府阀。

如何在保證數(shù)據(jù)存儲中的增刪改查效率呢缆镣?就成了一個必不可少的設(shè)計(jì)。

在Mysql這樣的數(shù)據(jù)存儲中總是少不了一個東西--->索引试浙,索引就類似于我們看書的目錄董瞻,使用書籍的目錄可以幫助快速的定位到知識點(diǎn)的頁數(shù),而索引也是同樣的目的田巴,快速檢索到數(shù)據(jù)钠糊。

那就可以總結(jié)出索引的目的:提高數(shù)據(jù)的檢索速度

索引的類型

既然索引有提高檢索的速度壹哺,那就給數(shù)據(jù)庫的查詢操作都加上索引抄伍,讓他們飛快的運(yùn)行,這事還真不能急管宵,為啥截珍?數(shù)據(jù)庫的索引種類有好多種,萬一索引用的不對箩朴,引發(fā)的不是加快數(shù)據(jù)庫的運(yùn)行岗喉,而是眾多的慢查詢會將整個數(shù)據(jù)庫拖垮。

用于提高讀寫效率的數(shù)據(jù)結(jié)構(gòu)種類這么多炸庞,那我們來了解下數(shù)據(jù)庫中常見的索引類型都有哪些沈堡。

索引類型 哈希索引 二叉樹 跳表 B+Tree

哈希索引

哈希索引簡單來說就是Key-Value模型,我們只要通過給定的Key就可以查找到對應(yīng)的Value燕雁,十分快速方便诞丽。

不過你要明白哈希索引是通過哈希函數(shù)對Key進(jìn)行計(jì)算,換算成數(shù)據(jù)存儲位置拐格,隨著數(shù)據(jù)量的增加僧免,不可避免會出現(xiàn)不同的Key經(jīng)過哈希函數(shù)計(jì)算后出現(xiàn)相同的數(shù)據(jù)存儲位置。

這種情況怎么解決呢捏浊?業(yè)界通用的方式是當(dāng)出現(xiàn)位置一樣的數(shù)據(jù)結(jié)果懂衩,會在該結(jié)果后面鏈接一個鏈表,將相同的數(shù)據(jù)放入到鏈表中金踪。

更進(jìn)一步當(dāng)相同位置中的數(shù)據(jù)越來越多浊洞,查詢數(shù)據(jù)時會將鏈表中的數(shù)據(jù)遍歷,速度也是慢胡岔,這時候可以采用將鏈表進(jìn)行樹化法希,二叉樹的查找速度還是很快的。

??圖是數(shù)據(jù)舉例說明:


哈希索引

哈希索引只適合用來查找等值的數(shù)據(jù)靶瘸,而不是適合范圍索引苫亦,排序等操作毛肋。常見的哈希索引是在Redis中。

二叉樹

數(shù)據(jù)結(jié)構(gòu)中存在數(shù)據(jù)結(jié)構(gòu)屋剑,雖然樹的結(jié)構(gòu)多種多樣润匙,但是常用的數(shù)據(jù)結(jié)構(gòu)是二叉樹,二叉樹是擁有兩個分叉的樹唉匾,分別為左子節(jié)點(diǎn)與右子節(jié)點(diǎn)孕讳。以此類推,動物中有八爪魚巍膘,同樣的也存在八叉樹厂财,你可以想象八叉樹是什么樣子。

二叉樹的特點(diǎn)是典徘,左節(jié)點(diǎn)的值<父節(jié)點(diǎn)<右節(jié)點(diǎn)蟀苛。如果要查找到一個值就可以按照子節(jié)點(diǎn)的順序進(jìn)行查找.

隨著數(shù)據(jù)量的增大,二叉樹的高度也會主鍵遞增逮诲,數(shù)據(jù)庫存儲的數(shù)據(jù)并不是都放到內(nèi)存中帜平,而是要放到磁盤上,磁盤的訪問速度是比內(nèi)存慢幾十倍梅鹦。

現(xiàn)在假如一個樹高30,每次搜索樹一次就需要訪問一次硬盤,一次訪問磁盤速度假設(shè)是10ms裆甩,樹高30至少需要訪問磁盤30次才能獲取到數(shù)據(jù),30*10=300ms齐唆。

如果數(shù)據(jù)更多嗤栓,樹高到100,獲取一次數(shù)據(jù)成本就很高了箍邮。

為了解決這個問題茉帅,可以使用N叉樹的方式來降低樹的高度,減少訪問磁盤的次數(shù)锭弊,這樣就能提高效率堪澎。

二叉樹

跳表

跳表是建立在多層級鏈表上的數(shù)據(jù)結(jié)構(gòu),通過一層層的鏈表查詢就提高了檢索數(shù)據(jù)的效率味滞。

B+Tree

Mysql中索引的實(shí)現(xiàn)是建立在數(shù)據(jù)庫引擎上的樱蛤,而在Mysql中有多個數(shù)據(jù)庫引擎,常用的數(shù)據(jù)庫引擎是InnoDB.

InnoDB引擎索引實(shí)現(xiàn)是使用B+Tree索引模型剑鞍,其實(shí)還有一種BTree模型昨凡,B+Tree是建立在BTree基礎(chǔ)上發(fā)展的。

B+Tree可以認(rèn)為是BTree的改進(jìn)版本:

注意子節(jié)點(diǎn)與葉子節(jié)點(diǎn)是不同的概念蚁署。把沒有子節(jié)點(diǎn)的節(jié)點(diǎn)叫做葉子節(jié)點(diǎn)

  • 在B+Tree中子節(jié)點(diǎn)只存儲索引便脊,而在B樹中是存儲數(shù)據(jù)的。
  • B樹中的葉子節(jié)點(diǎn)并不需要使用鏈表連串聯(lián)形用,而B+樹中是用鏈表連接起來的就轧。
  • B+樹中的葉子節(jié)點(diǎn)存儲數(shù)據(jù).

數(shù)據(jù)庫中每一個索引都能對應(yīng)到一顆B+樹证杭,一個表是可以存在多個B+樹田度。

不管是B+Tree還是BTree都是利用多叉樹(該樹有多少叉是根據(jù)頁的大小進(jìn)行計(jì)算好的妒御,索引會涉及到新增刪除,同樣的就會涉及到頁的分裂與合并)镇饺,保證不把所有的索引數(shù)據(jù)放入到內(nèi)存上乎莉,降低磁盤的訪問次數(shù)加快數(shù)據(jù)訪問。

索引的分類

Mysql中常用Innodb引擎,組織數(shù)據(jù)庫索引的方式就是B+Tree奸笤。

B+Tree是索引組織表惋啃,那在B+Tree有多少種索引的類型呢?

從不同的方向劃分可以劃分為不同的類型监右。

功能上區(qū)分

主要為普通索引边灭,主鍵索引,唯一索引健盒,前綴索引绒瘦,全文索引,哈希索引扣癣。

普通索引

普通索引就是我們常用的索引創(chuàng)建-> 創(chuàng)建單個索引惰帽,相關(guān)語句如下

alter table table_name add index index_name(column);
drop index index_name on table_name;
ALTER TABLE table_name DROP INDEX index_name

主鍵索引

主鍵索引是在普通索引的基礎(chǔ)上增加兩種約束條件分別為唯一和不能為空。主鍵索引在Innodb中用來維護(hù)索引組織的性質(zhì)父虑,所以该酗,在使用Innodb引擎時,建議你的表都設(shè)置主鍵士嚎。

創(chuàng)建主鍵可以在創(chuàng)建的表的時候指定 primary key('id'),也可以創(chuàng)建聯(lián)合主鍵primary key ('id','name').

創(chuàng)建主鍵的相關(guān)SQL

# 當(dāng)表里面沒有主鍵索引時呜魄,增加主鍵索引
ALTER TABLE table_name ADD PRIMARY KEY ( `id` )
# 刪除主鍵索引
ALTER TABLE table_name DROP INDEX name_index

唯一索引

唯一索引時在普通索引的基礎(chǔ)上增加唯一的約束,在插入相關(guān)數(shù)據(jù)時莱衩,會檢查該索引數(shù)據(jù)是否已經(jīng)存在數(shù)據(jù)庫中爵嗅。

使用下面的創(chuàng)建語句創(chuàng)建:

# 創(chuàng)建唯一索引
ALTER TABLE table_name ADD UNIQUE (`column`)
# 刪除索引
drop index index_name on table_name;

前綴索引

字符串在編程中經(jīng)常遇到的,比如常用的郵箱,一些業(yè)務(wù)場景中需要對某些字符串的前綴進(jìn)行匹配膳殷。

這就涉及到一個問題操骡,不能使用索引的話,就只能進(jìn)行全表掃描赚窃。數(shù)據(jù)量一大册招,該方式就會成為性能的瓶頸。

數(shù)據(jù)庫中的前綴索引就是解決字符串前綴匹配的問題勒极。

# 創(chuàng)建前綴索引
alter table table_name  add index index_name(columns(6));
# 刪除索引
drop index index_name on table_name;
# 怎么計(jì)算前綴索引設(shè)計(jì)幾個字符 使用下列語句進(jìn)行估算
select count(distinct 列名)/count(*)as a,COUNT(DISTINCT left(列名,100)) as b, COUNT(DISTINCT left(列名,110)) as c from 表名

前綴索引有一個缺點(diǎn)就是無法使用覆蓋索引的優(yōu)化是掰,必須回表查詢。

全文索引

全文索引是用來解決Mysql中文本匹配慢的問題辱匿,常使用like模糊搜索%內(nèi)容%键痛,沒法用到前面列舉的索引炫彩,這時候就可以嘗試使用全文索引來解決該問題。

相關(guān)SQL文件看下??

create fulltext index table_name
    on index_name(column,column);
alter table table_name
    add fulltext index index_name(column,column);

注意一點(diǎn)的是全文索引是有自己的匹配語法絮短,使用match和against關(guān)鍵字來進(jìn)行匹配??江兢。

select * from table_name where match(column,column) against('xxx xxx');

從索引個數(shù)上區(qū)分

從個數(shù)區(qū)分就是該索引郵幾個列組成。當(dāng)有多個列構(gòu)成就是聯(lián)合索引

  • 單個索引:只有一列創(chuàng)建的索引
  • 聯(lián)合索引:多列聯(lián)合組成的索引丁频。

單個索引的介紹不用多說杉允,這里主要說下聯(lián)合索引。

聯(lián)合索引

我們知道B+Tree樹這種形式的索引結(jié)構(gòu)是可以使用最左前綴席里,來定位記錄叔磷。十分恰當(dāng)?shù)穆?lián)合索引就需要使該規(guī)則才能發(fā)揮出強(qiáng)大的作用。

最左前綴

順便引出的問題就是我們在創(chuàng)建聯(lián)合索引的時候應(yīng)該怎么安排索引內(nèi)的字段順序奖磁?

當(dāng)當(dāng)前表是新建立的改基,還沒有其他索引可以根據(jù)業(yè)務(wù)需求進(jìn)行直接創(chuàng)建;如果表中已經(jīng)存在其他索引咖为,那可以通過調(diào)整順序幫助減少索引的創(chuàng)建秕狰。

每次創(chuàng)建一個新的索引,就會增加一部分的索引存儲空間案疲,隨著數(shù)據(jù)量的增加封恰,索引的存儲也會暴漲,所以在創(chuàng)建索引時褐啡,都需要考一個空間占用的原則诺舔。

當(dāng)有一個大字段和小字段組合成聯(lián)合索引時,大字段索引放在聯(lián)合索引的前面备畦。

比如現(xiàn)在需要根據(jù)郵件和年齡查詢數(shù)據(jù)低飒,但還有根據(jù)age以及email單獨(dú)查詢的需求。

一般第一個反應(yīng)就是創(chuàng)建三個索引懂盐,age,name,(name,age)/(age,name)褥赊。

而一般email的長度是大于age的,在有最左前綴的原則下莉恼,聯(lián)合索引第一個字段單獨(dú)查詢是可以使用索引拌喉。則這里選擇創(chuàng)建的索引就是age,name,(name,age)。

從磁盤角度區(qū)分

看一些數(shù)據(jù)庫資料總是聚簇索引俐银,非聚簇索引尿背,這兩種方式跟主鍵索引,普通索引又有什么區(qū)別捶惜?

聚簇索引田藐,非聚簇索引

其實(shí)就是一類內(nèi)容,只是根據(jù)分類的方式不同,叫的名字不同而已汽久。聚簇索引與非聚簇索引是指在磁盤上對數(shù)據(jù)的組織結(jié)構(gòu)不同鹤竭。

聚簇索引可認(rèn)為是磁盤將實(shí)際數(shù)據(jù)按照定物理地址進(jìn)行順序存放,并且與索引的順序是一致的景醇。那么當(dāng)索引是相鄰的臀稚,對應(yīng)的數(shù)據(jù)一定也是按照相鄰的順序存放。

磁盤對于順序讀取速度比磁盤隨機(jī)讀取的速度要快很多啡直;正因?yàn)榫鄞厮饕前凑瘴锢眄樞蜻M(jìn)行存儲烁涌,那一個表只能有一個聚簇索引苍碟,該索引在Mysql中是主鍵索引酒觅,當(dāng)然主鍵索引也是可以包含多個列的。

其他類型的索引都是被稱為非聚簇索引微峰。

非聚簇索引

)

使用非聚簇索引查詢數(shù)據(jù)舷丹,目的是先查到對應(yīng)的聚簇索引也就是主鍵索引。通過主鍵索引從而查詢到對應(yīng)的數(shù)據(jù)蜓肆。在這個過程中還涉及到兩個技術(shù)颜凯,分別為回表以及索引下推。

回表

回表很見到就是通過其他索引查到對應(yīng)的主鍵值仗扬,再使用主鍵值去表里面再檢索一遍數(shù)據(jù)症概。

那有沒有不用回表?有的早芭,在查詢的數(shù)據(jù)的時候彼城,查詢的索引中已經(jīng)包含要的字段,就不需要再使回表使用主鍵查詢數(shù)據(jù)退个,這句話可能有點(diǎn)蒙募壕,看下SQL你就明白了。

# 設(shè)置userid為普通索引
# 不使用覆蓋索引语盈,需要回表查詢
select * from user where userid=1
# 使用了覆蓋索引舱馅,這是因?yàn)閡serid的索引列上葉子節(jié)點(diǎn)就是存儲的主鍵id,不需要再回表
select ID from user where userid=1;

# 使用聯(lián)合索引也是可以做到的(userid,name)做一個聯(lián)合索引,索引列上有對應(yīng)的值刀荒,則不需要再回表查詢
select name from user where userid =1
索引下推

在Mysql5.6版本以前代嗤,查詢到的數(shù)據(jù)每條都需要重新回表查詢一次,而在5.6版本增加索引下推技術(shù)后缠借,可以直接在索引列中過濾掉不需要數(shù)據(jù)干毅,減少回表的次數(shù)。

注意該技術(shù)需要使用范圍是聯(lián)合索引(age,sex)

select * from user where  10<age and age>20 and sex=1;

首先使用索引查詢到年齡滿足第一條大于10小于20的人烈炭,同時索引列可以直接進(jìn)行判斷該用戶性別是不是滿足1(男性)溶锭,是就繼續(xù),不是該條記錄過濾掉符隙。

而在5.6以前滿足大于10小于20后趴捅,根據(jù)讀取到主鍵數(shù)據(jù)再進(jìn)行對比垫毙。回表的次數(shù)自然比使用索引下推技術(shù)版本多拱绑。

總結(jié)

本章從一個小問題引發(fā)了對索引的探索综芥,包含對現(xiàn)有的數(shù)據(jù)庫中常用的幾個索引技術(shù)進(jìn)行介紹,明白為什么Mysql會選擇B+Tree作為索引的檢索方式猎拨,并通過此方式梳理了Mysql中現(xiàn)有的索引技術(shù)膀藐。

希望這邊索引文章能幫助到你對索引的理解。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末红省,一起剝皮案震驚了整個濱河市额各,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吧恃,老刑警劉巖虾啦,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異痕寓,居然都是意外死亡傲醉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門呻率,熙熙樓的掌柜王于貴愁眉苦臉地迎上來硬毕,“玉大人,你說我怎么就攤上這事礼仗⊥驴龋” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵藐守,是天一觀的道長挪丢。 經(jīng)常有香客問我,道長卢厂,這世上最難降的妖魔是什么乾蓬? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮慎恒,結(jié)果婚禮上任内,老公的妹妹穿的比我還像新娘。我一直安慰自己融柬,他們只是感情好死嗦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著粒氧,像睡著了一般越除。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天摘盆,我揣著相機(jī)與錄音翼雀,去河邊找鬼。 笑死孩擂,一個胖子當(dāng)著我的面吹牛狼渊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播类垦,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼狈邑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蚤认?” 一聲冷哼從身側(cè)響起米苹,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎烙懦,沒想到半個月后驱入,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡氯析,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了莺褒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掩缓。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖遵岩,靈堂內(nèi)的尸體忽然破棺而出你辣,到底是詐尸還是另有隱情,我是刑警寧澤尘执,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布舍哄,位于F島的核電站,受9級特大地震影響誊锭,放射性物質(zhì)發(fā)生泄漏表悬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一丧靡、第九天 我趴在偏房一處隱蔽的房頂上張望蟆沫。 院中可真熱鬧,春花似錦温治、人聲如沸饭庞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舟山。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間累盗,已是汗流浹背六孵。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留幅骄,地道東北人劫窒。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像拆座,于是被迫代替她去往敵國和親主巍。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354