淺談MySQL Index
January 30, 2021資料庫是可以讓我們儲存資料和查詢資料的地方
假設我們想要儲存所有學生的基本資料 我們可以創建一個table
當然不能忘記要加一個student_id 不然要是有兩個人同名 我們就不知道誰是誰
這個student id同時也是primary key 不允許重複
那你說為什麼不用ssn當key就好呢 因為不是所有學生都有ssn(比如交換學生或是留學生)
所以ssn有個DEFAULT NULL
面試官來了
嗯這個table看起來不錯 那面試官問你你應該在哪個column建立索引呢
要是你回答 ssn 或是 first_name 或是last_name 或是 age 你就等著像Citron一樣被擊飛到外太空
答案應該是 取決於使用者的使用情況 觀察哪種queries最頻繁最吃資源 再考慮值不值得創建索引
MySQL 存儲原理
說破哪值幾文錢 大部分的MySQL實現都是使用Key-Value存儲每筆數據 而這個key-value本身則是用BTree存
所以我們剛剛創建的那個students
表 實際上每加一筆資料 我們加的是一筆key-value
(student_id) : (ssn, first_name, last_name, age)
就是因為這樣 所以當有人問說 誒誒我要知道student_id=5的名字 資料庫才能在很快的時間回傳給你
理解了原理之後 假設我們發現 資料庫的使用者很常在WHERE
裡面利用ssn
搜尋 比如
不難理解 每次執行這種查詢 都要整個table掃描去找ssn
解法就是 我們可以在ssn上加個索引
這樣的話 系統就會再創建一個Key-Value存儲
(ssn) : (student_id)
這樣我們就可以用很快的時間找到student_id 再用很快的時間從這個student_id去找到age或是first_name
當然 壞處就是要多花一點空間去存第二個Key-Value數據 還有每次有新學生加入的時候 有兩個Key-Value數據要改
來聊聊細節
我們已經不是學生了 上面那些只能用來騙騙面試官而已 我來問問你 創建index的時候 UNIQUE
是什麼意思?
這個意思就是 我知道這個column不會有重複 我才可以用UNIQUE INDEX
所以如果今天我們想對first_name創建索引 你必須拿掉UNIQUE
那內部的key-value就不能這麼存
(first_name) : (student_id)
因為有很多人會有一樣的first_name 所以上面那樣存沒法用 而是變成這麼存
(first_name, student_id) : ()
注意 這裡student_id會照順序存 比如說
(‘Johnson’, 2) : ()
(‘Johnson’, 5) : ()
(‘Johnson’, 8) : ()
我等於是在存儲的時候就幫你排序好了 減少每次查詢的時候需要花在排序的時間 所以下面這個查詢
就等於是這樣
創建索引除了讓我們查詢更快 也讓資料變得有序
再難一點
我們雖然讓資料有序 但這個有序卻是照著student_id排的序 如果我們想要
那就沒救了 那就只能找到所有first_name是Johnson的student_id之後 全部拿出來再排序
所以要是我們發現這種查詢很常發生
哇賽 每次都要把所有的Johnson的資料拿出來 假設有1000個Johnson 然後每次只顯示前三個 那實在太沒效率了
我們需要再創建一個索引
系統就會再創建一個Key-Value存儲
(first_name, last_name, student_id) : ()
這樣就容易了 因為對於同一個first_name來說 last_name是排序過的 就很好處理類似以下的查詢
但注意 無法search by last_name only
不夠過癮
不夠過癮是吧 那我們再說一點
1.固定的值比範圍查詢好
比如說如果有school_location這個column 而且我們有對這個column索引的話
這個寫法比較有效(如果你知道所有可能的school位置)
這個寫法比較沒效率
同理 如果status只能是1,2,3,4 那
比
有效率
2.輸出column的順序最好跟索引一樣
假設我們有對(first_name, last_name)做索引
那麼
會比
來得快
3.如果要對有索引的column做範圍查詢可以 但麻煩直接下範圍查詢 不要再加上其他操作
假設我們有對start_date下索引
比
有效不少 後者根本無法有效的利用BTree結構
4.直接對有索引的column下比較值
比
有效
結語
今天先講到這吧 大家有興趣的話再多講一些
總之要創建什麼index完全取決於使用者的常用查詢
更多更詳細的INDEX使用法 可以參考MySQL Doc