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

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

普通索引

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

唯一索引

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

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

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

全文索引

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

空間索引

空間索引是對空間數據類型的字段建立的索引,MySQL中的空間數據類型有四種,GEOMETRY、POINT、LINESTRING、POLYGON。在創建空間索引時,使用SPATIAL關鍵字。要求,引擎為Myisam,創建空間索引的列,必須將其聲明為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)

二、應用場景

現在你應該知道普通索引和唯一索引的區別,接下來看看在一些場景下如何選擇兩個索引。

丁老師文章中提到一個業務場景是市民系統,通過身份證號來查姓名。

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

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

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

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

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

Innodb存儲引擎的主鍵索引結構如下圖

普通索引數據結構如下圖

主鍵索引的葉子節點存儲的是對應主鍵的整行數據。

普通索引的葉子節點存儲的是對應的主鍵值。

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

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

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

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

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

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

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

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

四、從查詢的角度分析

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

普通索引

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

唯一索引

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

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

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

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

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

在Innodb存儲引擎下每頁的大小默認為16kb,這個參數也可以進行調整,參數為innodb_page_size。

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

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

五、了解change buffer

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

當需要更新card = 5這條記錄時,這條數據所在的數據頁在內存中就直接更新,如若不在的話就需要將更新的操作緩存在change buffer中。當下次查詢需要訪問這個數據頁時,將這個數據頁讀入內存,然后執行change buffer中與這個頁有關的操作。

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

當把change buffer中的數據應用到數據頁,得到最新結果的過程成為merge,另外數據庫正常關閉的過程中,也會執行merge操作。

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

注意

1、 數據從change buffer讀入內存是需要占用buffer pool的,使用change buffer可以避免占用內存。

2、change buffer 也是可以持久化數據的,change buffer 在內存中有拷貝,也會被寫入到磁盤。

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

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

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

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

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

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

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

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

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

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

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

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

思考:如何關閉change buffer

只需要將參數innodb_change_buffer_max_size = 0 即可。

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

第一種情況這條數據要更新的數據頁在內存中。

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

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

結論:當要更新的數據頁在內存中時,唯一索引就比普通索引多一次判斷。

第二種情況這條數據要更新的數據頁不在內存中。

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

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

結論:change buffer 當更新的數據不在數據頁中時,如果你的索引是普通索引則可以很顯著的提升性能。

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

八、總結

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

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

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

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

推薦閱讀更多精彩內容