Mysql合理建立索引,索引優化
- 2019 年 12 月 15 日
- 筆記
寫在前面
在我們日常使用資料庫的時候,肯定避免不了對資料庫的優化。那麼對資料庫的優化又少了不索引
的知識。
是的,建立索引
能極大地提高查詢的效率。那麼你知道嗎,如果合理建立索引,可以更大地榨出資料庫的性能——也就等同於進一步提高查詢效率。
寫下這篇文章就是為了記錄一下對索引的優化,合理建立索引。
什麼是索引
MySQL官方對索引的定義為:索引(Index)是幫助MySQL高效獲取數據的數據結構。
我們可以簡單理解為:快速查找排好序的一種數據結構。Mysql索引主要有兩種結構:B+Tree索引和Hash索引。
索引就相當於字典前的目錄,如果這個目錄劃分規劃更好,那麼我們找到想要的數據就會更方便,也就提高了查詢的效率。
索引的類型有:
- normal:表示普通索引
- unique:表示唯一的,不允許有重複值的索引
- full textl: 表示全文搜索的索引,用於搜索很長一篇文章的時候,效果最好。
建立索引的場景
索引不是越多越好,因為每次更新、插入數據,就需要對索引文件進行變動,會減低該類型操作的執行效率。
如果建立索引的欄位太多,影響就會很大。
所以我們只在合理的欄位上建立索引
。
- 在經常用來當查詢條件
(where,on,group by,order by)
的欄位上建立索引。 - 在數據的維度比較大的欄位上建立索引。
- 對數據較小的列使用索引,可以使索引文件更小,同時記憶體中也可以裝載更多的索引鍵。
- 為較長的字元串使用前綴索引。
比如數據的長度大部分是150個位元組,我們只建立前100個位元組的索引。
常見的可以用於建立索引的欄位場景:
① 用戶id 在訂單表中的用戶id欄位上建立索引,根據用戶id篩選訂單,則會很快查詢出用戶的訂單。 用戶一般是在自己的後台查看訂單,所以表中的其他用戶數據與他無關,如果沒有建立索引,每次查詢都是全表掃描,則會很慢。(我們每個人在淘寶平台上占的訂單比例都不到0.0001)
② 商品名 同上,如果不建立索引,我們在淘寶輸入框搜索鍵盤
,怎麼快速查詢出鍵盤商品?
③ 日期 常用的活躍數據,一般都是是最近產生的,很少人沒事去翻半年前的訂單數據吧?
合適的還有很多很多場景,需要各位小夥伴自己好好思量。
索引不生效的場景
並不是建立了索引就在查詢語句中生效。
- 當語句中帶有or的時候,索引會失效
- 當索引的欄位使用like查詢,並且使用了
前通配
比如%Siam
,索引失效。後通配會生效Siam%
- 當索引的欄位是字元類型,但是儲存的值是數字,比如 user_name:』123456』,在查詢語句中要 user_name = 『123456』而
不能
user_name = 123456 否則發生類型轉換,索引失效,其他類型的欄位 比如日期等 也同理 - 當使用的條件語句,預計結果數量超過全表數據的一定比例時,會轉為全表掃描(mysql一般是30%左右)這就是為什麼在建立索引的時候要選擇維度(區別度)比較高的列,性別這種欄位不適合建立索引。
- 語句中出現列數據運算才判斷的,比如where age – 10 > 0 每一行都要運算之後才知道是否大於0 所以就是全表掃描,如果age > 10 則可使用索引。使用函數轉換列數據也一樣原理。
- 組合索引時使用的條件語句。
上面舉例的一些場景都是比較容易理解的。組合索引還沒涉及,往下繼續介紹。
mysql中,多個索引同時使用?
先來看一條語句
select * from test where user_name = 'siam_007' and create_time = 1563280050
假設在這個表中,user_name欄位和create_time都是建立了索引的。也沒有發生數據類型轉換等情況。
問題:該語句有幾個索引生效?
是2個嗎?並不是這樣子的。
雖然兩個欄位的索引都沒有問題,如果單獨使用也都能生效。
但是:MySQL會從可用的索引中猜測出效率最高的一個索引並使用它
怎麼證明?使用explain
語句(詳解可以在網上其他資料找到)
只要在sql語句最前面加上該語法,則會顯示查詢類型相關的資訊。
Explain select * from mysql_index_test where user_name = 'siam_007' and create_time = 1563280050

我建立了兩個索引,都能用,都是本次查詢只能使用一個。
基於這個情況,會引申出
兩個知識點
- 組合索引
- 多個單欄位索引衝突
組合索引
先來說說組合索引吧,我們在新建索引的時候(可視化軟體),是這樣子的頁面

當我們勾選上2個或者2個以上 就能把它叫為組合索引
了
可以看到還有調整順序的功能
在組合索引中,欄位順序
也是極為重要的。
假設我們有這樣一個索引:new : a,b,c 欄位
在查詢時使用where a = 1 and b = 2 and c= 3
。那麼這個語句肯定是生效的。
如果我們使用where b = 2 and c =3
沒有a條件 而a又是在組合索引中最左側的,那麼索引就不會生效。
還是要掃描全部行
where a,c where a,b where b,a,c
這樣子使用都是可以生效的。
組合索引要注意欄位順序,是指在創建索引時候的排序,而不是sql語句中where的順序,我們使用where b = 2 and a = 1 and c = 3
也是 可以生效的
那麼組合索引的欄位順序要如何排比較好?
後面會有新的一篇文章會講這個
多個單欄位索引衝突
如果我們在表中,擁有兩個索引,比如user_name 用戶名, user_phone 用戶手機號
現在有這樣子的數據量: 100W條數據 user_name=』我是用戶名』 100條數據 user_phone=』110′ 5條數據 user_name=』我是用戶名』 and user_phone=』110′
假設有這樣子一條語句:
select * from test where user_name = '我是用戶名' and user_phone='110'
有兩個欄位都有索引可用,mysql會選擇一個使用。這是屬於mysql的內部處理判斷
正常情況下,如果用user_phone索引生效的話,會很快得到結果(先篩選出100條 再篩選)
如果user_name生效,則要先篩選100W條數據,再篩選user_phone
mysql的內部判斷可能使得user_name索引生效,此時效率就會很低了,我們可以強制使用某個索引
phone是索引名 是新建的時候填的
select * from test index(phone) where user_name = '我是用戶名' and user_phone='110'
此種情況出現的概率比較小,畢竟mysql的解釋器很複雜,也做了足夠多的優化。只有排查慢日誌並且分析確定索引衝突的情況才需要強制使用索引。
優化 (總結)
- 只在經常使用的欄位上建立索引,否則會拖慢數據更新和插入的速度。
- 只在維度高的欄位上建立索引,否則會使得數據比例過大,轉為全表掃描。
- 優先對數據量比較小的欄位建立索引,可以使索引文件更小,同時記憶體中也可以裝載更多的索引鍵。
- 規範sql語句的生成,禁止發生
列運算
、類型轉換
的發生。 - 長字元串可以使用前綴索引,只對字元串的前面一定字元長度建立索引。
- 組合索引的順序合理優化(會有新文章介紹)
- 當多個單欄位索引發生衝突時,強制使用某個索引。