如何選擇普通索引和唯一索引《死磕MySQL系列 五》

系列文章

一、原來一條select語句在MySQL是這樣執(zhí)行的《死磕MySQL系列 一》

二、一生摯友redo log、binlog《死磕MySQL系列 二》

三、MySQL強(qiáng)人“鎖”難《死磕MySQL系列 三》

四、S 鎖與 X 鎖的愛恨情仇《死磕MySQL系列 四》

image

看過前幾期文章的伙伴會發(fā)現(xiàn)并沒有聊過關(guān)于索引和事務(wù)的知識點,這兩個大點再之前的文章中已經(jīng)寫過了。

這里給大家一個傳送門點擊直接查看哈!

揭開MySQL索引神秘面紗

上來就問MySQL事務(wù),瑟瑟發(fā)抖...

MVCC:聽說有人好奇我的底層實現(xiàn)

幻讀:聽說有人認(rèn)為我是被MVCC干掉的

接下來打開普通索引和唯一索引的世界。

一、了解普通索引和唯一索引

普通索引

MySQL中基本索引類型,沒有什么限制,允許在定義索引的列中插入重復(fù)值和空值,純粹為了查詢數(shù)據(jù)更快一點。

唯一索引

索引列中的值必須是唯一的,但是允許為空值。

主鍵索引是一種特殊的唯一索引,不允許有空值。

擴(kuò)展一下其它兩中索引,知識點放在一起記憶會更好

全文索引

只能在char,varchar,text類型字段上使用全文索引,介紹了要求,說說什么是全文索引,就是在一堆文字中,通過其中的某個關(guān)鍵字等,就能找到該字段所屬的記錄行,比如有“你是個靚仔,靚女。。。”通過靚仔,可能就可以找到該條記錄。

空間索引

空間索引是對空間數(shù)據(jù)類型的字段建立的索引,MySQL中的空間數(shù)據(jù)類型有四種,GEOMETRY、POINT、LINESTRING、POLYGON。在創(chuàng)建空間索引時,使用SPATIAL關(guān)鍵字。要求,引擎為Myisam,創(chuàng)建空間索引的列,必須將其聲明為not null。

索引添加方式

1、 主鍵索引:alter table table_name add primary key (column)

2、 唯一索引:alter table table_name add unique (column)

3、普通索引:alter table table_name add index index_name (column)

4、全文索引:alter table table_name add fulltext (column)

5、多列索引:alter table table_name add index index_name (column1,column2,column3)

二、應(yīng)用場景

現(xiàn)在你應(yīng)該知道普通索引和唯一索引的區(qū)別,接下來看看在一些場景下如何選擇兩個索引。

丁老師文章中提到一個業(yè)務(wù)場景是市民系統(tǒng),通過身份證號來查姓名。

這里咔咔也借用這個場景來給大家通過咔咔的思路描述一下這個流程。

執(zhí)行語句為select name from user where card = '6104301996xxxxxxxx';

這個場景第一反應(yīng)肯定是給card創(chuàng)建一個索引,但創(chuàng)建什么索引呢?主鍵索引肯定不建議使用。

思考:為什么不能用身份證號來作為主鍵索引?

三、為什么不能用太大的值作為主鍵

Innodb存儲引擎的主鍵索引結(jié)構(gòu)如下圖

image

普通索引數(shù)據(jù)結(jié)構(gòu)如下圖

image

主鍵索引的葉子節(jié)點存儲的是對應(yīng)主鍵的整行數(shù)據(jù)。

普通索引的葉子節(jié)點存儲的是對應(yīng)的主鍵值。

如果說B+Tree讀取數(shù)據(jù)的深度是三層,每個磁盤的大小為16kb。

那在B+Tree中非葉子節(jié)點可以存儲多少數(shù)據(jù)呢!一般來說我們每個表都會存在一個主鍵。

根據(jù)三層來計算,第一層跟第二層存儲的是key值,也就是主鍵值。

都知道int類型所占的內(nèi)存時4Byte(字節(jié)),指針的存儲就給個6Byte,一共就是10Tybe,那么第一層節(jié)點就可以存儲16 * 1000 /10 = 1600。

同理第二層每個節(jié)點也是可以存儲1600個key。

第三層是葉子節(jié)點,每個磁盤存儲大小同樣安裝BTree的計算一樣,每條數(shù)據(jù)占1kb。

在B+Tree中三層可以存儲的數(shù)據(jù)就是1600 * 1600 * 16 = 40960000

結(jié)論:若主鍵過大會直接影響索引存儲的數(shù)據(jù)量,所以非常不建議使用過大的數(shù)據(jù)作為主鍵索引。

四、從查詢的角度分析

假設(shè)現(xiàn)在要查card = 5 這條記錄,查詢過程為,先通過B+樹從樹根開始,按層搜索到葉子節(jié)點,然后通過二分法來定位card = 5 的這條記錄。

普通索引

對于普通索引來說當(dāng)找到card = 5這條記錄后,還會繼續(xù)查找,直到碰到第一個不滿足card = 5的記錄為止。

唯一索引

對于唯一索引就非常簡單的了,唯一索引的特性就是數(shù)據(jù)唯一性,所以查到card = 5這條記錄后就不在查找下一條記錄了。

普通索引多查詢的一次對性能影響大嗎?

這個影響幾乎可以忽略,在之前的幾期文章中咔咔給大家普及了一個名詞“局部性原理”。

數(shù)據(jù)和程序都有聚集成群的傾向,在訪問了一條數(shù)據(jù)之后,在之后有極大的可能再次訪問這條數(shù)據(jù)和這條數(shù)據(jù)的相鄰數(shù)據(jù)。

所以說MySQL的Innodb存儲引擎,在讀取數(shù)據(jù)時也會采取這種局部性原理,每次讀取的數(shù)據(jù)是16kb,也就是一頁。

在Innodb存儲引擎下每頁的大小默認(rèn)為16kb,這個參數(shù)也可以進(jìn)行調(diào)整,參數(shù)為innodb_page_size。

但有一種情況雖說幾率非常低,但還是需要知道的。

當(dāng)索引為普通索引時,查到的數(shù)據(jù)正好是一頁的最后一個數(shù)據(jù),此時就需要讀取下一頁的數(shù)據(jù),這個操作是有點復(fù)雜,但對于現(xiàn)在的CPU來說可以忽略不計。

五、了解change buffer

首先,需要先了解一個新的知識點change buffer。

當(dāng)需要更新card = 5這條記錄時,這條數(shù)據(jù)所在的數(shù)據(jù)頁在內(nèi)存中就直接更新,如若不在的話就需要將更新的操作緩存在change buffer中。當(dāng)下次查詢需要訪問這個數(shù)據(jù)頁時,將這個數(shù)據(jù)頁讀入內(nèi)存,然后執(zhí)行change buffer中與這個頁有關(guān)的操作。

接著,了解另一個新的知識點merge。

當(dāng)把change buffer中的數(shù)據(jù)應(yīng)用到數(shù)據(jù)頁,得到最新結(jié)果的過程成為merge,另外數(shù)據(jù)庫正常關(guān)閉的過程中,也會執(zhí)行merge操作。

結(jié)論:更新操作將記錄先記錄到change buffer中,可以減少磁盤I/O,語句執(zhí)行速度會提升。

注意

1、 數(shù)據(jù)從change buffer讀入內(nèi)存是需要占用buffer pool的,使用change buffer可以避免占用內(nèi)存。

2、change buffer 也是可以持久化數(shù)據(jù)的,change buffer 在內(nèi)存中有拷貝,也會被寫入到磁盤。

六、change buffer在什么條件下使用

思考:為什么唯一索引使用不到change buffer

唯一索引肯定是用不到,對于這個答案如果你感覺有點不適,就需要在回到之前幾期文章再好好看看。

唯一索引插入一行數(shù)據(jù)時都會執(zhí)行一次查詢操作判斷表中是否已經(jīng)存在這條記錄,判斷是否違反唯一約束,既然必須得把數(shù)據(jù)頁的數(shù)據(jù)讀入內(nèi)存,那還用change buffer個什么勁啊!

因此,只有普通索引可以使用。

在上文中知道了將change buffer數(shù)據(jù)讀入內(nèi)存時是需要占用buffer pool的內(nèi)存,因此在MySQL中也給了一個參數(shù)來設(shè)置change buffer的大小。跟其它的數(shù)據(jù)單位可能有點出入,若設(shè)置為30,就表示change buffer只占用buffer pool內(nèi)存的30%。

思考:在什么場景下不能使用change buffer?

change buffer的作用是將更新的動作緩存下來,所以對一個數(shù)據(jù)頁做merge時,change buffer記錄的變更越多,收益就越大。

但也并不是所有場景都適用,咔咔目前所開發(fā)的是一款賬款軟件,大部分更新后都是立馬查看,這種情況是不是就違背了上面說的對一個數(shù)據(jù)頁做merge時,change buffer記錄的越多,收益越大。

因此,只有寫多讀少的場景,change buffer才能發(fā)揮非常大的作用。

思考:為什么更新完立馬查詢change buffer就沒多大用處了呢?

一條記錄發(fā)起更新操作后,先記錄到change buffer 中,接著,當(dāng)查詢的數(shù)據(jù)在這個數(shù)據(jù)頁時會立即觸發(fā)merge,這樣隨機(jī)訪問的IO的次數(shù)不會減少,反而增加了change buffer的維護(hù)代價。所以說這種業(yè)務(wù)模式使用change biffer會起到反作用。

思考:如何關(guān)閉change buffer

只需要將參數(shù)innodb_change_buffer_max_size = 0 即可。

七、從更新語句性能的影響的角度分析

第一種情況這條數(shù)據(jù)要更新的數(shù)據(jù)頁在內(nèi)存中。

唯一索引:在內(nèi)存中查找是否有這條記錄,不存在時則插入這個值。

普通索引:直接更新需要更新的值即可。

結(jié)論: 當(dāng)要更新的數(shù)據(jù)頁在內(nèi)存中時,唯一索引就比普通索引多一次判斷。

第二種情況這條數(shù)據(jù)要更新的數(shù)據(jù)頁不在內(nèi)存中。

唯一索引:需要將這條數(shù)據(jù)所在的數(shù)據(jù)頁讀入內(nèi)存中,查找是否存在這條記錄,然后更新數(shù)據(jù)。

普通索引:將這條要更新的數(shù)據(jù)記錄在change buffer即可。

結(jié)論: change buffer 當(dāng)更新的數(shù)據(jù)不在數(shù)據(jù)頁中時,如果你的索引是普通索引則可以很顯著的提升性能。

注意: 當(dāng)你把一個索引從普通索引改為唯一索引時一定要注意change buffer的影響,會直接影響內(nèi)存命中率。

八、總結(jié)

回到文章主題如何選擇普通索引和唯一索引,在查詢方面兩者是沒有什么差別的,主要是在更新操作上的影響。

如果你的業(yè)務(wù)跟咔咔的場景一樣,更新后立馬要對這個記錄查詢,那么就可以選擇直接關(guān)閉change buffer。

若不是這種場景,則盡量選擇普通索引,使用change buffer可以非常明顯的提升更新性能。

堅持學(xué)習(xí)、堅持寫作、堅持分享是咔咔從業(yè)以來所秉持的信念。愿文章在偌大的互聯(lián)網(wǎng)上能給你帶來一點幫助,我是咔咔,下期見。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,179評論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,628評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,444評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,948評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,185評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,717評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,794評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,414評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,750評論 2 370

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