MySQL數(shù)據(jù)庫之索引

  • 索引的使用方法
  • 索引的數(shù)據(jù)結(jié)構(gòu)
  • 不同存儲引擎中的索引實(shí)現(xiàn)方式

MySQL數(shù)據(jù)庫表的訪問方式又兩種:順序訪問、索引訪問廉侧。
1页响、順序訪問:
直接進(jìn)行全表掃描,根據(jù)條件逐行記錄判斷段誊,指導(dǎo)找到相應(yīng)結(jié)果為止闰蚕。面對當(dāng)前互聯(lián)時代,數(shù)據(jù)量都是成百上千萬的存在连舍,這樣的訪問方式將會及其緩慢没陡,不僅消耗資源還大大影響了效率∷魃停基本不會使用此方式盼玄。
2、索引訪問:
為了解決大數(shù)據(jù)量情況下也能快速訪問潜腻,就必須采用索引的方式埃儿。索引訪問是通過遍歷索引來直接訪問表中記錄行的方式(前提是在該列上有創(chuàng)建索引)。

一融涣、MySQL數(shù)據(jù)庫索引的使用

1桥氏、創(chuàng)建索引的幾種方式:

  • 創(chuàng)建表的時候同時創(chuàng)建索引:
CREATE TABLE table_name(          # table_name:表名
id INT NOT NULL PRIMARY KEY,      # PRIMARY KEY MySQL創(chuàng)建表之后會默認(rèn)創(chuàng)建一個主鍵索引   
user_name VARCHAR(16) NOT NULL,  
INDEX idx_user_name (user_name(16))  # index_name 索引名稱吹菱,user_name索引列们衙,(16)長度瞬逊,如果字段類型是BLOB或TEXT必須制定索引列長度,如果字段類型是CHAR或者VARCHAR可忽略指定長度  
);
  • 直接創(chuàng)建索引
CREATE UNIQUE INDEX u_idx_id ON table_name(id);   # 創(chuàng)建唯一索引忽你,一般用于主鍵幼东,或者其他不能重復(fù)的常用查詢字段。
CREATE INDEX index_name ON table_name(user_name); # 普通索引 user_name->表字段名
  • 修改表結(jié)構(gòu)的方式創(chuàng)建索引
ALTER TABLE table_name ADD UINDEX u_idx_id (id);                # 創(chuàng)建唯一索引
ALTER TABLE table_name ADD INDEX idx_user_name (user_name);     # 創(chuàng)建普通索引

2科雳、刪除索引

ALTER TABLE table_name DROP INDEX u_idx_id;    # 通過ALTER命令刪除索引 table_name:表名根蟹,u_idx_id:索引名
DROP INDEX idx_user_name ON table_name;        # 通過DROP命令直接刪除索引 idx_user_name:索引名,table_name:表名

3炸渡、查看索引

SHOW INDEX FROM table_name; #table_name:表名

二娜亿、MySQL數(shù)據(jù)庫索引相關(guān)數(shù)據(jù)結(jié)構(gòu)

二叉樹、紅黑樹蚌堵、B-Tree、B+Tree、Hash

1吼畏、為什么二叉樹和紅黑樹不適合作為索引的數(shù)據(jù)結(jié)構(gòu)督赤?

  • 二叉樹不適合的原因:
    當(dāng)某表的索引列為依次遞增序列,如此的話泻蚊,二叉樹將會變成一個鏈表形式躲舌,不利于快速查找,因此二叉樹不適合作為索引的數(shù)據(jù)結(jié)構(gòu)性雄。 在查找的過程中會多次進(jìn)行磁盤I/O没卸,將會影響系統(tǒng)性能、查詢速度較慢秒旋。
  • 紅黑樹不適合的原因:
    紅黑樹是一個平衡二叉樹约计,在插入數(shù)據(jù)的時候,為了保持平衡二叉樹的特性會發(fā)生自旋迁筛,相比二叉樹來效率稍微高一些煤蚌。
    不適合作為索引的主要原因是當(dāng)數(shù)據(jù)量上百萬之后,表的記錄越多樹的高度越高细卧,樹的高度不可控尉桩,也會使得磁盤I/O次數(shù)增多,也是相當(dāng)耗費(fèi)資源贪庙,影響系統(tǒng)性能蜘犁。

2、B-Tree作為索引:

  • 在紅黑樹上的基礎(chǔ)上進(jìn)行的改造止邮,讓每個節(jié)點(diǎn)可以橫向存儲多個元素这橙,從而使得樹的高度降低,減少的磁盤的I/O次數(shù)农尖,從而提高性能析恋,這也就是B-Tree的數(shù)據(jù)結(jié)構(gòu)。
  • B-Tree特點(diǎn):
    1.葉子節(jié)點(diǎn)具有相同的深度盛卡,葉子節(jié)點(diǎn)的指針為空助隧,葉子節(jié)點(diǎn)之間沒有指針連接
    2.所有索引元素不重復(fù)滑沧;
    3.節(jié)點(diǎn)中的數(shù)據(jù)索引從左至右依次遞增并村。
  • 如圖下結(jié)構(gòu):


    B-Tree結(jié)構(gòu).png

其中,data可能存儲的是當(dāng)前索引列所屬行的其他字段所有數(shù)據(jù)滓技,當(dāng)表字段較多哩牍,則data占用空間就會變大,當(dāng)前大節(jié)點(diǎn)所能存儲的索引總個數(shù)就會變少令漂,從而當(dāng)表數(shù)據(jù)量過大的時候樹的高度也會變得不可控膝昆。(MySQL對大節(jié)點(diǎn)的默認(rèn)大小是16K)

  • 查看MySQL文件頁大小的的SQL語句:
SHOW GLOBAL STATUS LIKE 'Innodb_page_size'; # 可修改丸边,建議不要修改
  • B-Tree作為索引存在的弊端:
    1.如果不是按照索引的最左列開始查找,則無法使用索引荚孵。
    2.不能跳過索引中的列
    3.如果查詢中有某列的范圍查詢妹窖,則其右邊所有列都無法使用索引優(yōu)化查詢。

3收叶、B+Tree

MySQL數(shù)據(jù)庫索引真正的數(shù)據(jù)結(jié)構(gòu)是采用B+Tree實(shí)現(xiàn)的(B-Tree的變種)骄呼。

  • B+Tree特點(diǎn):
    1.非葉子節(jié)點(diǎn)不存儲data,只存儲索引(冗余)判没;
    2.葉子節(jié)點(diǎn)包含所有索引字段蜓萄;
    3.葉子節(jié)點(diǎn)從左至右依次遞增,葉子節(jié)點(diǎn)采用指針連接澄峰,提高區(qū)間訪問的性能(模糊查詢)嫉沽。
  • 結(jié)構(gòu)如下圖(高度為3):


    B+Tree結(jié)構(gòu).png
  • 計(jì)算MySQL的索引能存儲多多少個元素:
    為減少磁盤I/O,大節(jié)點(diǎn)不能存儲更多的索引摊阀。
    1).第一層(根節(jié)點(diǎn)):MySQL表主鍵一般用bigint(占用磁盤空間8B)耻蛇,指針占用6B,此時一個索引元素(默認(rèn)指針和索引是成對出現(xiàn)的)占用空間為14B胞此,大節(jié)點(diǎn)的默認(rèn)大小為16K臣咖。如此,計(jì)算一個大節(jié)點(diǎn)可以存儲的索引元素個數(shù)為:16K / (8B + 6B) ≈ 1170個索引
    2).第二層(非葉子節(jié)點(diǎn)):根據(jù)第一層可知漱牵,第二層應(yīng)該存在1170大節(jié)點(diǎn)夺蛇, 每個節(jié)點(diǎn)都存在1170個索引元素。
    3).第三層(葉子節(jié)點(diǎn)):存在1170 * 1170個大節(jié)點(diǎn)酣胀,假設(shè)data和小節(jié)點(diǎn)總共占用1K刁赦,則一個葉子節(jié)點(diǎn)可以存在16個索引元素。
    綜上闻镶,高度為3的B+Tree總共存儲元素個數(shù)應(yīng)該為:1170 * 1170 * 16個索引元素(大概2000萬+)甚脉。
  • 優(yōu)點(diǎn):
    1.B+Tree的高度遠(yuǎn)小于B-Tree(原因:B+Tree的非葉子節(jié)點(diǎn)不存儲data,只存儲索引铆农,每個節(jié)點(diǎn)的大小固定牺氨,所以B+Tree的節(jié)點(diǎn)可以存儲更多的索引。)墩剖。
    2.磁盤I/O次數(shù)極少猴凹,一般需要2次磁盤I/O(根節(jié)點(diǎn)存在于內(nèi)存)。
    3.MySQL底層對B+Tree樹葉子節(jié)點(diǎn)的指針做了優(yōu)化岭皂,改為了雙向指針郊霎。 葉子節(jié)點(diǎn)的指針就是為了便于范圍查詢,提高范圍查詢的效率爷绘,避免多次遍歷B+Tree书劝。

4进倍、Hash表作為索引

Hash索引結(jié)構(gòu)的特殊性,其檢索效率非常高庄撮,索引的檢索可以一次定位背捌,不像B-Tree索引需要從根節(jié)點(diǎn)到枝節(jié)點(diǎn)毙籽,最后才能訪問到頁節(jié)點(diǎn)這樣多次的I/O訪問洞斯,所以Hash索引的查詢效率要遠(yuǎn)高于B-Tree索引。
之所以在使用中不采用Hash索引的主要原因是Hash索引不支持范圍查詢坑赡、不支持?jǐn)?shù)據(jù)排序操作烙如。也有可能發(fā)生Hash碰撞,但發(fā)生碰撞的概率極小毅否。如果對某表的操作操作99%
都是等值查詢則可以考慮使用Hash索引亚铁,否則不建議采用此索引。

三螟加、MySQL數(shù)據(jù)庫存儲引擎索引實(shí)現(xiàn)

1徘溢、MyISAM存儲引擎(非聚簇索引)

  • MyISAM將數(shù)據(jù)文件和索引文件分開存儲
  • 主鍵索引和非主鍵索引結(jié)構(gòu)相似
  • 建表語句
CREATE TABLE table_myisam (           # table_myisam:表名稱 
  id BIGINT(11) NOT NULL,
  user_id VARCHAR(16) NOT NULL,
  user_name VARCHAR(16) NOT NULL,
) ENGINE=MYISAM DEFAULT CHARSET=utf8  # EGINE=MYISAM 指定表的存儲引擎
  • 該表對應(yīng)文件結(jié)構(gòu)(windows文件目錄在MySQL安裝目錄下的Data目錄下,Linux目錄默認(rèn)在/var/lib/mysql/目錄下):


    MyISAM存儲引擎的表對應(yīng)的文件結(jié)構(gòu).png
  • 索引結(jié)構(gòu):


    MyISAM索引結(jié)構(gòu).png
SQL查詢過程:

SQL語句:

SELECT * FROM table_myisam WHERE id = 49;

查詢過程:
通過B+Tree索引找到49所在的節(jié)點(diǎn)捆探,將該節(jié)點(diǎn)數(shù)據(jù)寫入內(nèi)存然爆,根據(jù)該節(jié)點(diǎn)data的信息直接去取數(shù)據(jù)文件的記錄,再將結(jié)果寫入內(nèi)存黍图。

2曾雕、InnoDB存儲引擎(聚簇索引)

  • 表數(shù)據(jù)文件本身就是按照B+Tree組織的一個索引結(jié)構(gòu)文件

  • 聚簇索引的葉子節(jié)點(diǎn)包含了完整的數(shù)據(jù)記錄

  • 主鍵索引和輔助索引的主要區(qū)別:
    1.主鍵索引:葉子節(jié)點(diǎn)的data存儲該記錄其他所有字段。
    2.輔助索引(非主鍵索引):葉子節(jié)點(diǎn)的data存儲該記錄的主鍵助被。

  • 建表語句

CREATE TABLE table_innodb (
  id BIGINT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,    # PRIMARY KEY:主鍵剖张,AUTO_INCREMENT:自增
  user_id VARCHAR(16) NOT NULL,
  user_name VARCHAR(16) NOT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;                   # ENGINE=INNODB:設(shè)定存儲引擎為InnoDB
  • 對應(yīng)文件結(jié)構(gòu)(文件目錄同上所述MyISAM存儲引擎的文件目錄):


    InnoDB存儲引擎的表對應(yīng)的文件結(jié)構(gòu).png
  • 索引結(jié)構(gòu)
    1.主鍵索引:


    InnoDB存儲引擎主鍵索引結(jié)構(gòu).png

    2.輔助索引(非主鍵索引):


    InnoDB存儲引擎非主鍵索引結(jié)構(gòu).png
面試題:
  • Q : 聚簇(聚集)索引和非聚簇(稀疏、非聚集)索引的概念揩环?
    A : 聚簇索引就是將索引和數(shù)據(jù)記錄存放在一起搔弄,非聚簇索引就是索引和數(shù)據(jù)記錄是分開存儲的。因此丰滑,MyISAM存儲引擎的索引就是非聚簇索引顾犹,InnoDB存儲引擎的索引就是聚簇索引。
  • Q:為什么InnoDB表必須有主鍵吨枉,并且推薦使用整型的自增主鍵蹦渣?
    A:
    1.必須有主鍵? InnoDB的表數(shù)據(jù)就是按照B+Tree形式存儲貌亭,所以必須要有主鍵并且默認(rèn)有主鍵索引柬唯,MySQL的InnoDB存儲引擎底層就是如此設(shè)計(jì)的。(沒有明確指定主鍵的建表語句圃庭,MySQL底層會自動建一列字段(rowid)為主鍵锄奢,數(shù)據(jù)每插入一行rowid都會生成一個唯一的整型值)失晴。
    2.整型主鍵?假設(shè)主鍵采用UUID的存儲方式拘央,MySQL會將UUID進(jìn)行編碼計(jì)算(逐個比較每個字符的ASCII碼進(jìn)行比較大型科ā)得到一個值進(jìn)行大小比較建立B+Tree索引數(shù)據(jù)文件。并且UUID占用磁盤空間較大灰伟,所以也不適合作為主鍵拆又。
    3.自增?如果是整型自增的話栏账,按照索引結(jié)構(gòu)一般來insert數(shù)據(jù)說都是往后面添加元素帖族,不需要過多的判斷大小,改變數(shù)據(jù)指針指向挡爵。如果不是自增竖般,會改變樹的結(jié)構(gòu),不容易維護(hù)茶鹃,影響系統(tǒng)性能涣雕。
  • Q:為什么非主鍵索引結(jié)構(gòu)葉子節(jié)點(diǎn)存儲的是主鍵值?
    A:為保障數(shù)據(jù)一致性(如果一個表既存在主鍵索引也存在非主鍵索引闭翩,在insert之前需要先維護(hù)需要維護(hù)好索引結(jié)構(gòu)挣郭,再講數(shù)據(jù)寫入表中,則意味著insert就可能出現(xiàn)類似分布式事務(wù)的問題男杈,此時需要同時維護(hù)兩個索引的數(shù)據(jù)丈屹,并且要保持一致之后才能完成真正的插入操作,不僅維護(hù)量大伶棒,而且會牽扯性能問題)旺垒,并且可以節(jié)省存儲空間(非主鍵索引的data只需要存儲主鍵值,大大節(jié)省了存儲空間)肤无。
3先蒋、聯(lián)合索引
  • 創(chuàng)建聯(lián)合索引:
# table_innodb : 表名, s_index:索引名宛渐, user_id竞漾、user_name:字段名
ALTER TABLE table_innodb ADD INDEX s_index (user_id, user_name, birth_date);    # 通過修改表結(jié)構(gòu)的方式創(chuàng)建聯(lián)合索引
CREATE INDEX s_index ON table_innodb (user_id, user_name, birth_date);          # 直接創(chuàng)建聯(lián)合索引
  • 底層存儲結(jié)構(gòu):


    聯(lián)合索引.png
  • 解釋:
    根據(jù)如上聯(lián)合索引SQL建立所得的聯(lián)合索引樹結(jié)構(gòu)圖大致如上,在實(shí)際比較過程中遵循最左匹配原則窥翩,先比較user_id业岁,從左至右依次遞增;當(dāng)user_id結(jié)果相同是再比較user_name寇蚊,根據(jù)user_name的ASCII碼值從左至右依次遞增笔时;當(dāng)user_name結(jié)果也相同的時候,再比較birth_date仗岸。如此方式建立出樹結(jié)構(gòu)允耿。
  • 實(shí)際工作之中建議采用聯(lián)合索引的方式借笙,可以節(jié)省空間。
  • 聯(lián)合索引就是將多個字段存儲到同一個節(jié)點(diǎn)之上较锡。
  • 聯(lián)合索引排序順序根據(jù)建立索引時候的字段順序從左至右一次比較順序

不妥之處還請指正...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末业稼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蚂蕴,更是在濱河造成了極大的恐慌低散,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掂墓,死亡現(xiàn)場離奇詭異谦纱,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)君编,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來川慌,“玉大人吃嘿,你說我怎么就攤上這事∶沃兀” “怎么了兑燥?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長琴拧。 經(jīng)常有香客問我降瞳,道長,這世上最難降的妖魔是什么蚓胸? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任挣饥,我火速辦了婚禮,結(jié)果婚禮上沛膳,老公的妹妹穿的比我還像新娘扔枫。我一直安慰自己,他們只是感情好锹安,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布短荐。 她就那樣靜靜地躺著,像睡著了一般叹哭。 火紅的嫁衣襯著肌膚如雪忍宋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天风罩,我揣著相機(jī)與錄音糠排,去河邊找鬼。 笑死泊交,一個胖子當(dāng)著我的面吹牛乳讥,可吹牛的內(nèi)容都是我干的柱查。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼云石,長吁一口氣:“原來是場噩夢啊……” “哼唉工!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起汹忠,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤淋硝,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后宽菜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谣膳,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年铅乡,在試婚紗的時候發(fā)現(xiàn)自己被綠了继谚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡花履,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出挚赊,到底是詐尸還是另有隱情诡壁,我是刑警寧澤妹卿,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布懊直,位于F島的核電站火鼻,受9級特大地震影響魁索,放射性物質(zhì)發(fā)生泄漏粗蔚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一义桂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蹈垢,春花似錦慷吊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至沐祷,卻和暖如春嚷闭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赖临。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留灾锯,地道東北人兢榨。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像顺饮,于是被迫代替她去往敵國和親吵聪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內(nèi)容