@(數據庫)[MySQL]html
數據庫索引,是數據庫管理系統中一個排序的數據結構,以協助快速查詢,更新數據庫表中數據。
有兩種基本的索引類型
順序索引:基於值的順序排序
散列索引:基於將值平均分佈在若干散列桶中,一個值所屬的散列通是有一個函數決定的,該函數被稱爲 散列函數
順序索引中,根據包含記錄是否按照搜索碼制定的順序排序能夠分爲彙集索引和非彙集索引mysql
聚簇索引和非聚簇索引並非單獨的索引類型,而是一種數據存儲方式 [高性能 MySQL]
索引的缺點主要是針對不合理索引而言的,對於開發者而言,索引維護所耗費的資源和索引所提供的快速查詢能力節省的時間資源二者進行取捨。
MySQL 存儲索引的時候通常咱們沒有明確之處其他結構就是指的是 B-Tree 數據結構存儲索引。 參考資料衛星數據:指的是索引元素所指向的數據記錄,好比數據庫的某一行。算法
什麼是 B-Tree?一個 m 階的 B 樹有如下幾個特徵。sql
模擬查找文件29的過程:(1) 根據根結點指針找到文件目錄的根磁盤塊1,將其中的信息導入內存。【磁盤IO操做1次】數據庫
(2) 此時內存中有兩個文件名17,35和三個存儲其餘磁盤頁面地址的數據。根據算法咱們發現17<29<35,所以咱們找到指針p2。服務器
(3) 根據p2指針,咱們定位到磁盤塊3,並將其中的信息導入內存。【磁盤IO操做2次】數據結構
(4) 此時內存中有兩個文件名26,30和三個存儲其餘磁盤頁面地址的數據。根據算法咱們發現26<29<30,所以咱們找到指針p2。函數
(5) 根據p2指針,咱們定位到磁盤塊8,並將其中的信息導入內存。【磁盤IO操做3次】性能
(6) 此時內存中有兩個文件名28,29。根據算法咱們查找到文件29,並定位了該文件內存的磁盤地址。大數據
分析上面的過程,發現須要3次磁盤IO操做和3次內存查找操做。關於內存中的文件名查找,因爲是一個有序表結構,能夠利用折半查找提升效率。至於3次磁盤IO操做時影響整個B-tree查找效率的決定因素。
固然,若是咱們使用平衡二叉樹的磁盤存儲結構來進行查找,磁盤IO操做最少4次,最多5次。並且文件越多,B-tree比平衡二叉樹所用的磁盤IO操做次數將越少,效率也越高。
B 樹中每一個節點都具備衛星數據
插入(insert)操做:插入一個元素時,首先在B-tree中是否存在,若是不存在,即在葉子結點處結束,而後在葉子結點中插入該新的元素,注意:若是葉子結點空間足夠,這裏須要向右移動該葉子結點中大於新插入關鍵字的元素,若是空間滿了以至沒有足夠的空間去添加新的元素,則將該結點進行「分裂」,將一半數量的關鍵字元素分裂到新的其相鄰右結點中,中間關鍵字元素上移到父結點中(固然,若是父結點空間滿了,也一樣須要「分裂」操做),並且當結點中關鍵元素向右移動了,相關的指針也須要向右移。若是在根結點插入新元素,空間滿了,則進行分裂操做,這樣原來的根結點中的中間關鍵字元素向上移動到新的根結點中,所以致使樹的高度增長一層。
例:自頂向下查找4的節點位置,發現4應當插入到節點元素3,5之間
節點3,5已是兩元素節點,沒法再增長。父親節點 2, 6 也是兩元素節點,也沒法再增長。根節點9是單元素節點,能夠升級爲兩元素節點。因而拆分節點3,5與節點2,6,讓根節點9升級爲兩元素節點4,9。節點6獨立爲根節點的第二個孩子
刪除(delete)操做:首先查找B-tree中需刪除的元素,若是該元素在B-tree中存在,則將該元素在其結點中進行刪除,若是刪除該元素後,首先判斷該元素是否有左右孩子結點,若是有,則上移孩子結點中的某相近元素到父節點中,而後是移動以後的狀況;若是沒有,直接刪除後,移動以後的狀況.。刪除元素,移動相應元素以後,若是某結點中元素數目小於ceil(m/2)-1,則須要看其某相鄰兄弟結點是否豐滿(結點中元素個數大於ceil(m/2)-1),若是豐滿,則向父節點借一個元素來知足條件;若是其相鄰兄弟都剛脫貧,即借了以後其結點數目小於ceil(m/2)-1,則該結點與其相鄰的某一兄弟結點進行「合併」成一個結點,以此來知足條件。那我們經過下面實例來詳細瞭解吧。
例:刪除11節點
刪除11後,節點12只有一個孩子,不符合B樹規範。所以找出12,13,15三個節點的中位數13,取代節點12,而節點12自身下移成爲第一個孩子。(這個過程稱爲左旋)
B+Tree 是對於 B-Tree 的一種變體,有着比 B-Tree 更高的查詢效率。
一個 m 階的 B 樹有着以下特色
根節點的最大元素等榮譽整個樹的最大元素,葉子節點包含了全量元素信息,而且每個葉子節點都帶有指向下一個節點的指針,造成了一個有序鏈表.
在 B+Tree 樹中,只有葉子節點保存衛星數據.
須要補充的是,在數據庫的彙集索引(Clustered Index)中,葉子節點直接包含衛星數據。在非彙集索引(NonClustered Index)中,葉子節點帶有指向衛星數據的指針。
因爲 B+Tree 樹的中間節點沒有衛星數據,因此一樣大小的磁盤也(1~4K)能夠容納更多的元素,意味着查詢的 IO 次數越少。
另外,B+Tree 的查詢必須最終查詢到葉子節點,和 B-Tree 不一樣,查詢性能最穩定,並且在範圍查詢中,比起只能以來繁瑣的中序遍歷的 B 樹,更有效率。
綜合來看,B+Tree 對比 B-Tree 有三大優點:
關於哈希索引,目前 MySQL 中只有 Memory 和 NDB 兩種引擎支持,詳細瞭解能夠參考這篇文章 MySQL索引之哈希索引,本文不在贅述。
理解了索引的數據結構以後咱們就理解了索引在建立和使用上的一些方法(如下所描述的索引均指的是 B-Tree 索引)。
create table People ( last_name varchar(50) not null, first_name varchar(50) not null, dob date not null, gendar enum('m','f') not null, key(last_name, first_name, dob) );
select * from People where last_name = 'Allen' and first_name = 'Cuba' and dob = '1999-01-01';
select * from People where last_name = 'Allen';
select * from People where last_name like 'A%';
select * from People where last_name > 'Allen' and last_name < 'Bob';
select * from People where last_name = 'Allen' and last_name like 'B%';
只訪問索引的查詢
select last_name,
first_name, dob
from People
where last_name = 'Allen'
and first_name = 'Cuba' and dob = '1999-01-01';
select * from People where first_name = 'Allen';
select * from People where last_name = 'Allen' and dob = '1999-01-01';
select * from People where last_name = 'Allen' and first_name like 'J%' and dob = '1999-01-01';
- 最左前綴匹配原則,很是重要的原則,mysql會一直向右匹配直到遇到範圍查詢(>、<、between、like)就中止匹配,好比a = 1 and b = 2 and c > 3 and d = 4 若是創建(a,b,c,d)順序的索引,d是用不到索引的,若是創建(a,b,d,c)的索引則均可以用到,a,b,d的順序能夠任意調整。
- 使用獨立的列
- 多列索引:MySQL 從5.0以後的更新版本引入了一種叫索引合併的策略,關於這項策略能夠參考MySQL 優化之 index merge
- =和in能夠亂序,好比a = 1 and b = 2 and c = 3 創建(a,b,c)索引能夠任意順序,mysql的查詢優化器會幫你優化成索引能夠識別的形式
- 儘可能選擇區分度高的列做爲索引,區分度的公式是count(distinct col)/count(*),表示字段不重複的比例,比例越大咱們掃描的記錄數越少,惟一鍵的區分度是1,而一些狀態、性別字段可能在大數據面前區分度就是0,那可能有人會問,這個比例有什麼經驗值嗎?使用場景不一樣,這個值也很難肯定,通常須要join的字段咱們都要求是0.1以上,即平均1條掃描10條記錄
- 索引列不能參與計算,保持列「乾淨」,好比from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,緣由很簡單,b+樹中存的都是數據表中的字段值,但進行檢索時,須要把全部元素都應用函數才能比較,顯然成本太大。因此語句應該寫成create_time = unix_timestamp(’2014-05-29’);
- 儘可能的擴展索引,不要新建索引。好比表中已經有a的索引,如今要加(a,b)的索引,那麼只須要修改原來的索引便可
一些有價值的參考資料