佳木斯湛栽影视文化发展公司

主頁 > 知識庫 > Mysql數(shù)據(jù)庫索引面試題(程序員基礎(chǔ)技能)

Mysql數(shù)據(jù)庫索引面試題(程序員基礎(chǔ)技能)

熱門標(biāo)簽:百度競價排名 網(wǎng)站排名優(yōu)化 地方門戶網(wǎng)站 服務(wù)外包 呼叫中心市場需求 Linux服務(wù)器 AI電銷 鐵路電話系統(tǒng)

引言

索引是Mysql的一塊硬骨頭,但是對于程序猿來說又是十分重要的基礎(chǔ)技能。在平常的項目開發(fā)中,它是重要的SQL優(yōu)化手段。在求職面試中,它是面試官常常用來考察求職者數(shù)據(jù)庫性能優(yōu)化方面的重要考量。因此透徹的掌握索引原理,并能夠?qū)⑵溥\(yùn)用到數(shù)據(jù)庫查詢實戰(zhàn)是每個程序猿必備的能力。本文將從索引原理、索引設(shè)計原則方面闡述Mysql索引。相信閱讀完本文之后,在Mysql索引查詢數(shù)據(jù)理解這塊完全可以征服阿里面試官。準(zhǔn)備好了嗎?我們發(fā)車了。

索引原理

在進(jìn)行索引設(shè)計以及優(yōu)化之前,我們先深入理解下索引的原理。因為所有的設(shè)計以及優(yōu)化一定是建立在你對原理的透徹理解的基礎(chǔ)上。

很多人都知道,在進(jìn)行SQL查詢時,同樣一張表、同樣的數(shù)據(jù)。不加索引以及加索引進(jìn)行數(shù)據(jù)查詢。兩者差別很多。那么到底是為什么有這種差距。簡單來說,如果把業(yè)務(wù)數(shù)據(jù)比作為一本字典的話,那么索引就是這本字典的目錄。如果我讓你查一個字,在你不使用目錄查的時候,那只能一頁一頁的翻,運(yùn)氣不好的話可能要翻到最后一頁才能查到想要的字,這就是傳說中的全表掃描。但是如果我們通過目錄來查找,那么可以很快定位字所在頁,進(jìn)而查找到對應(yīng)的字??吹搅税桑饕耐驮谟谔岣邤?shù)據(jù)查詢的效率。好了,現(xiàn)在我們對于索引有了感性的認(rèn)識。那么我們接下來就深入了解下。

我們都知道在Mysql中索引的數(shù)據(jù)結(jié)構(gòu)是B+樹(這里不再說明B樹、Hash索引等結(jié)構(gòu)的優(yōu)劣,不是本文的重點(diǎn)),那么我們就一步一步來看看,索引在磁盤中的B+樹是怎么長成的。

1、數(shù)據(jù)頁

在日常的項目開發(fā)中,我們的業(yè)務(wù)數(shù)據(jù)大部分都存在關(guān)系型數(shù)據(jù)中。那么數(shù)據(jù)庫中各個表中的數(shù)據(jù)最終也都是存儲在服務(wù)器的硬盤當(dāng)中的。不知道大家有沒有想過這個數(shù)據(jù)到底是怎么存儲的呢?實際上Mysql數(shù)據(jù)庫中我們每天都在使用的數(shù)據(jù)庫表是對于人來理解的邏輯表。它實際在磁盤當(dāng)中是通過一頁頁的數(shù)據(jù)頁進(jìn)行存儲的。數(shù)據(jù)頁是磁盤與內(nèi)存交互的基本單位,MysqlInnodb存儲引擎,實際通過buffer pool與磁盤中的數(shù)據(jù)頁進(jìn)行交互,而不是直接操作磁盤中的數(shù)據(jù)頁。數(shù)據(jù)頁的結(jié)構(gòu)如下圖所示:

同時相鄰的數(shù)據(jù)頁之間通過雙向鏈表來維護(hù)數(shù)據(jù)頁之間的相互引用。如下圖所示,橙紅色部分即為數(shù)據(jù)頁,中間的小框框可以理解為一條條具體的數(shù)據(jù)。MysqlInnoDB存儲引擎數(shù)據(jù)頁大小是16KB。MysqlInnodb存儲引擎通過頁號來唯一定位一個數(shù)據(jù)頁,因此每個數(shù)據(jù)頁都有自己的頁號。通過上圖可知,每個數(shù)據(jù)頁都有都有對應(yīng)的Page Header,在Page Header中保存了當(dāng)前數(shù)據(jù)頁的頁號,以及其下一頁的頁號和上一頁的頁號。

相鄰的數(shù)據(jù)之間通過指針進(jìn)行互相引用,指針標(biāo)注數(shù)據(jù)頁的頁號,每個數(shù)據(jù)頁中存儲了連續(xù)的一段數(shù)據(jù),每個數(shù)據(jù)行中的記錄頭部存有下一行記錄真實數(shù)據(jù)的地址偏移量,簡單理解為擁有指針指向下一行數(shù)據(jù)的地址。因此在數(shù)據(jù)頁的內(nèi)部,實際是關(guān)于數(shù)據(jù)行的單向鏈表。這個單向鏈表是關(guān)于主鍵id的,從小到大進(jìn)行排列。


從上述的數(shù)據(jù)頁結(jié)構(gòu)可知,每次進(jìn)行數(shù)據(jù)插入時User Records區(qū)域就會變大,相應(yīng)的的User Record區(qū)域就會減少。當(dāng)User Record區(qū)域消耗完之后,就會發(fā)生頁分裂,形成新的數(shù)據(jù)頁。這里需要注意的是,如果我們使用的是Mysql中的自增主鍵,那么可以保證按照id的增長順序進(jìn)行數(shù)據(jù)行排列,但是如果主鍵是我們自己設(shè)置的并不是自增長的,那么有可能出現(xiàn)后面插入的數(shù)據(jù)的主鍵值小于前面數(shù)據(jù)的主鍵值,那么在進(jìn)行頁分裂的時候,Mysql會按照主鍵大小重新進(jìn)行排列。此處不知道大家有沒有疑問,為什么一定要按照主鍵大小進(jìn)行排列呢?實際上和后續(xù)的數(shù)據(jù)查詢有關(guān)系,數(shù)據(jù)頁中的數(shù)據(jù)按照主鍵順序進(jìn)行排列是索引可以正常運(yùn)行的基礎(chǔ)。大致的過程如下圖所示:

2、頁目錄

每個數(shù)據(jù)頁都有自己的頁目錄上面頁結(jié)構(gòu)中的Page Directory,這個頁目錄的作用實際上就是用來進(jìn)行數(shù)據(jù)行定位的。數(shù)據(jù)頁中的數(shù)據(jù)實際上是按組分配的,頁目錄中的不同的槽位,其實是對應(yīng)了數(shù)據(jù)頁中的不同的分組,查詢數(shù)據(jù)時,通過id找到對應(yīng)的槽,再根據(jù)對應(yīng)的槽來知道對應(yīng)在數(shù)據(jù)頁中的數(shù)據(jù)行分組,遍歷數(shù)據(jù)行分組中的數(shù)據(jù)直到找到對應(yīng)的數(shù)據(jù)。

3、索引原理分析

(1)索引基礎(chǔ)

有了上面兩節(jié)的數(shù)據(jù)頁的基礎(chǔ)知識之后,我們再來探討索引原理就更加容易理解了。在沒有索引時,數(shù)據(jù)查詢都是進(jìn)行全表掃描。遍歷查詢數(shù)據(jù)頁中的每個數(shù)據(jù)行,再遍歷所有的數(shù)據(jù)頁,知道找到符合條件的數(shù)據(jù)項。因此查詢效率十分的低下。那么應(yīng)該怎么才能提供數(shù)據(jù)查詢的效率呢?能不能像字典的目錄一樣,也搞個主鍵目錄來進(jìn)行數(shù)據(jù)頁號的定位呢?答案是肯定的,Mysql實際也正是這么做的。Mysql通過主鍵目錄實際就是傳說中的主鍵索引,實現(xiàn)數(shù)據(jù)的查詢優(yōu)化。在主鍵目錄中包含了兩個重要元素,一個是數(shù)據(jù)頁中最小的主鍵,另一個是當(dāng)前數(shù)據(jù)頁的頁號。這樣可以通過這個主鍵目錄方面的進(jìn)行數(shù)據(jù)查詢。

舉個栗子,如果此時想要查詢主鍵id=5的數(shù)據(jù),那么首先在主鍵目錄中進(jìn)行查找。此時發(fā)現(xiàn)主鍵id=5大于主鍵id=1,但是又小于id=8,那么就可以確定實際上數(shù)據(jù)實際是在頁號為1的數(shù)據(jù)頁中的。

當(dāng)然在實際在Mysql中會有很多的數(shù)據(jù)頁,因此對應(yīng)的主鍵索引也會很多,那么此時就需要通過二分查找的方式進(jìn)行數(shù)據(jù)頁定位,再查找到對應(yīng)的數(shù)據(jù)。

(2)索引頁

如今當(dāng)下,各個互聯(lián)網(wǎng)公司迅猛發(fā)展,對應(yīng)的業(yè)務(wù)量也是十分巨大。因此數(shù)據(jù)庫中的數(shù)據(jù)量也是十分龐大的。表中的數(shù)據(jù)幾百萬、上千萬可能很常見,按照上述的主鍵目錄,那么就需要存儲大量的主鍵與數(shù)據(jù)頁號。即便是進(jìn)行二分查找,其數(shù)據(jù)查詢效率也是比較低的。

Mysql實際是將索引說句存儲在索引頁中的,當(dāng)數(shù)據(jù)量比較大時候,對應(yīng)的索引也會比較多,因此通過專門的索引頁來存儲索引數(shù)據(jù)。另外在這些索引頁的上層又通過主鍵與索引頁號來繼續(xù)進(jìn)行索引頁的查詢定位,因此我們得到如下的結(jié)構(gòu)。其中的id號指的是對應(yīng)最小的id號。


如果索引頁中的數(shù)據(jù)越來越多,索引頁同樣會進(jìn)行頁分裂。這樣索引頁也就形成了不同的層級,索引頁層、索引頁、數(shù)據(jù)頁這三個頁數(shù)據(jù)就形成了我們說的B+樹。下圖就是索引的B+樹結(jié)構(gòu),通過它完成數(shù)據(jù)查詢效率遠(yuǎn)高于全表掃描。B+的葉子節(jié)點(diǎn)才會存儲數(shù)據(jù),下圖是一種主鍵索引,也叫聚簇索引。其實我們可以看出來,它的根本思想就是分而治之的思想。數(shù)據(jù)量很大是吧,那我就把數(shù)據(jù)分成很多的數(shù)據(jù)頁,數(shù)據(jù)頁很多是吧,那我就通過索引頁來組織數(shù)據(jù)頁,索引頁很多是吧,那就再通過索引頁來索引。


我們再來看下,數(shù)據(jù)查詢在B+樹中的查詢過程。舉個栗子,如當(dāng)前需要查詢id為3的數(shù)據(jù),那么將在索引頁中判斷應(yīng)該走索引頁為3的索引頁。那么在索引頁為3中繼續(xù)判斷id=1應(yīng)該走索引頁為1的索引頁,在索引頁中判斷應(yīng)該頁號為1的數(shù)據(jù)頁,在此數(shù)據(jù)頁中遍歷最終查詢到對應(yīng)的數(shù)據(jù)。

以上通過索引頁與數(shù)據(jù)頁組成的B+樹就是聚簇索引,當(dāng)然我們也可以通過其他字段來建立普通索引。知識普通索引會的葉子節(jié)點(diǎn)存儲的是對應(yīng)的主鍵id,而不是具體的數(shù)據(jù),索引會存在回表的問題,即查詢到對應(yīng)的id之后,還需要根據(jù)id繼續(xù)到聚簇索引中查詢具體的數(shù)據(jù),通過這樣的操作才能查詢到select *的所有數(shù)據(jù)。當(dāng)然我們可以通過覆蓋索引的方式避免這樣的查詢浪費(fèi)。

總結(jié)

本文通過一步步圖解的方式,為大家拆解MysqlInnoDB的索引原理,同時構(gòu)建出對應(yīng)的B+樹索引結(jié)構(gòu)。闡述了數(shù)據(jù)查詢的具體過程。相信大家對于索引這塊有了更加深刻的理解,后面會從實戰(zhàn)的角度出發(fā),分析下如何設(shè)計索引以及如何應(yīng)對索引失效的問題。

您可能感興趣的文章:
  • MYSQL數(shù)據(jù)庫基礎(chǔ)之Join操作原理
  • MySQL系列之開篇 MySQL關(guān)系型數(shù)據(jù)庫基礎(chǔ)概念
  • Python基礎(chǔ)之操作MySQL數(shù)據(jù)庫
  • MySql數(shù)據(jù)庫基礎(chǔ)知識點(diǎn)總結(jié)
  • 一篇文章帶你了解MySQL數(shù)據(jù)庫基礎(chǔ)

標(biāo)簽:蘭州 銅川 崇左 衡水 黃山 湖南 仙桃 湘潭

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Mysql數(shù)據(jù)庫索引面試題(程序員基礎(chǔ)技能)》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266
    大余县| 古浪县| 密山市| 潜江市| 濮阳市| 平顺县| 永靖县| 长乐市| 大埔区| 山东省| 盘锦市| 东明县| 米林县| 麦盖提县| 永丰县| 南溪县| 宜兰县| 拜城县| 双江| 夹江县| 体育| 河源市| 上高县| 望奎县| 洛宁县| 东丰县| 拜泉县| 子长县| 神木县| 达孜县| 广州市| 建德市| 健康| 扶风县| 深水埗区| 龙南县| 麦盖提县| 岳普湖县| 巴林左旗| 图片| 东乡族自治县|