在學習索引的時候,經常會看到回表、覆蓋索引、索引下推、頁分裂等等概念,本篇就常見概念進行介紹和總結,但願能幫助你們快速掌握這些「高大上」的概念。mysql
索引基於B+樹,要想更好地理解這些概念建議先了解談談MySQL索引底層實現之數據結構和數據結構之B+樹算法
根據葉子節點的內容, 索引類型分爲主鍵索引和非主鍵索引。(mysql索引的數據結構是B+樹,對這方面知識看不懂的能夠參考)sql
基於主鍵索引和普通索引的查詢有什麼區別?性能優化
普通索引查詢方式,則須要先搜索索引樹,獲得主鍵值,再到主鍵索引樹按主鍵值搜索一次,這個過程稱爲回表。數據結構
也就是說,基於非主鍵索引的查詢須要多掃描一棵索引樹。 所以, 咱們在應用中應該儘可能使用主鍵查詢。函數
什麼是頁分裂?性能
若是R5所在的數據頁已經滿了, 根據B+樹的算法, 這時候須要申請一個新的數據頁,而後挪動部分數據過去。這個過程稱爲頁分裂。 固然有分裂就有合併。當相鄰兩個頁因爲刪除了數據,利用率很低以後, 會將數據頁作合併。 合併的過程, 能夠認爲是分裂過程的逆過程mysql索引
頁分裂的壞處學習
除了性能外, 頁分裂操做還影響數據頁的利用率。本來放在一個頁的數據, 如今分到兩個頁中,總體空間利用率下降大約50%。優化
如何避免頁分裂?
使用自增主鍵。每次插入一條新記錄, 都是追加操做,都不涉及到挪動其餘記錄,也不會觸發葉子節點的分裂。
自增主鍵的其餘好處
因爲每一個非主鍵索引的葉子節點上都是主鍵的值。,若是用身份證號作主鍵, 那麼每一個二級索引的葉子節點佔用約20個字節, 而若是用整型作主鍵, 則只要4個字節, 若是是長整型(bigint)則是8個字節。顯然, 主鍵長度越小, 普通索引的葉子節點就越小, 普通索引佔用的空間也就越小。
有沒有什麼場景適合用業務字段直接作主鍵的呢?
好比,有些業務的場景需求是這樣的:
因爲沒有其餘索引, 因此也就不用考慮其餘索引的葉子節點大小的問題。這時候咱們就要優先考慮上一段提到的「儘可能使用主鍵查詢」原則, 直接將這個索引設置爲主鍵,能夠避免每次查詢須要搜索兩棵樹。
非彙集索引的B+樹節點存儲的是索引列和主鍵,假如想要拿到完整數據的話還得根據主鍵去主鍵索引樹回表,這樣性能很差,若是咱們要查詢獲得的數據就是索引列和主鍵中的數據,就不要回表。這樣只須要在一棵索引樹上就能獲取SQL所需的全部列數據無需回表的索引稱爲覆蓋索引
因爲覆蓋索引能夠減小樹的搜索次數, 顯著提高查詢性能, 因此使用覆蓋索引是一個經常使用的性能優化手段。
B+樹這種索引結構, 能夠利用索引的「最左前綴」來定位記錄。
索引樹排序規則:在對聯合索引創建索引樹時,會按照索引字段的順序依次排序。以(name,age,address)這個聯合索引爲例,首先按照name排序完,在name排序值相同時繼續按照age排序。
最左匹配:在mysql創建聯合索引時還會遵循最左前綴匹配的原則,即最左優先,在檢索數據時從聯合索引的最左邊開始匹配(左邊的匹配不上,後面也不會再去匹配了)。同時,索引只能用於查找key是否存在(相等),遇到範圍查詢 (>、<、between、like
左匹配)等就不能進一步匹配了,後續退化爲線性查找。所以,列的排列順序決定了可命中索引的列數
在創建聯合索引的時候, 如何安排索引內的字段順序?
對字符串的前幾個字符(具體是幾個字符在創建索引時指定)創建索引,這樣創建起來的索引佔用空間更小
對字符串創建普通索引和前綴索引的語句以下:
# 普通字符串索引 alter table SUser add index index1(email); # 前綴索引,索引長度爲6 alter table SUser add index index2(email(6));
前綴索引的優點和損失
優點:佔用的空間會更小
損失:會增長額外的記錄掃描次數
使用前綴索引,定義好長度, 就能夠作到既節省空間,又不用額外增長太多的查詢成本。
當要給字符串建立前綴索引時如何肯定應該使用多長的前綴?
前綴索引確定會損失區分度,咱們須要提早預設一個能夠接受的損失比列,使用count計算出多種長度的損失比例,選擇低於損失比例的最短長度。
第一步:計算算出這個列上有多少個不一樣的值:
select count(distinct email) as L from SUser
第二步:計算不一樣長度去重後有多少數據:
select count(distinct left(email,4)) as L4, count(distinct left(email,5)) as L5, count(distinct left(email,6)) as L6, count(distinct left(email,7)) as L7, from SUser;
第三步:選擇合適的長度
在返回的L4~L7中,找出不小於 L * 95%的值,假設這裏L六、L7都知足,你就能夠選擇前綴長度爲6。
前綴索引對覆蓋索引的影響
使用前綴索引就不能使用覆蓋索引對查詢性能進行優化了。由於索引只包含了字符串的部分數據。
遇到前綴的區分度不夠好的狀況時,咱們要怎麼辦?
上一段咱們說到知足最左前綴原則的時候,最左前綴能夠用於在索引中定位記錄。 這時,你可能要問,那些不符合最左前綴的部分, 會怎麼樣呢?
mysql> select * from tuser where name like '張%' and age=10 and ismale=1;
咱們仍是以市民表的聯合索引(name, age) 爲例。 若是如今有一個需求: 檢索出表中「名字第一個字是張, 並且年齡是10歲的全部男孩」。 那麼, SQL語句是這麼寫的:
你已經知道了前綴索引規則, 因此這個語句在搜索索引樹的時候, 只能用 「張」, 找到第一個知足條件的記錄ID3。 固然, 這還不錯, 總比全表掃描要好。而後呢?固然是判斷其餘條件是否知足。
在MySQL 5.6以前, 只能從ID3開始一個個回表。 到主鍵索引上找出數據行, 再對比字段值。
而MySQL 5.6 引入的索引下推優化(indexcondition pushdown), 能夠在索引遍歷過程當中, 對索引中包含的字段(age)先作判斷, 直接過濾掉不知足條件的記錄, 減小回表次數。
本文記錄比較零散,若是有模棱兩可或者不對的地方歡迎你們指正。