Mysql系列(十) Msql之InnoDB索引

2021-10-08 18:53:23 字數 3869 閱讀 8316

innodb儲存引擎支援以下幾種常見的索引:

這裡的雜湊索引是前面提到過的自適應雜湊索引。為innodb自己視情況而定建立的,不能進行認為干預。

b+樹索引就是傳統意義上的索引。注意的是b不是代表binary,而是代表balance。

可以看到下圖的兩顆都是二叉查詢樹,但是因為構建的方式不同。右圖的二叉樹查詢效率就很低了。

由此引出了平衡二叉樹,在符合二叉查詢樹的基礎上要求任何節點的兩個子樹高度差最大為1.

b+樹索引分為聚集索引和輔助索引,其內部都是b+樹索引。兩者的區別是聚集索引節點存放著所有的資料,輔助索引存放指向聚集索引的偏移量。每個葉子節點稱為資料頁,每個資料頁之間通過雙向鍊錶進行連線。由於實際的資料頁只能按照一顆b+樹進行排序。因此一張表只能有乙個聚集索引。在多數情況下,查詢優化器更傾向於採用聚集索引,因為其能直接在葉子節點上找到資料。

聚集索引順序儲存並不是在物理上連續而是在邏輯上連續,雙向鍊錶保證了他的連續性。雙向列表包含頁與頁之間的和每個頁中記錄之間的。

輔助索引也稱為非聚集索引,葉子節點並不包含行記錄的全部資料。葉子節點除了包含鍵值外,每個葉子節點中的索引行還包含乙個書籤。該書籤用來告訴innodb儲存引擎**可以找到與索引相對應的行資料。複製索引可以有多個。如果乙個高度為3的輔助索引,聚集索引樹的高度同樣為3,如果對輔助索引進行搜尋,那麼一共需要6次邏輯io訪問得到最終的結果。

b+樹索引的**並不是總從中間開始的,如果這樣可能會造成空間的浪費。如下:

因此innodb儲存引擎可以根據一些頭資訊來決定向左還是向右**。隨機插入則採用取頁的中間記錄作為**點的記錄。

並不是所有的查詢列都需要新增索引,那麼什麼時候應該新增索引呢?一般經驗是,在訪問表中很少一部分時使用b+樹索引才有意義。比如,對於性別字段、地區字段、型別字段,他們的可選擇性範圍很小,稱為低選擇性,即不適合建索引。那麼如何檢視索引是否是高選擇性呢?可以通過show index結果中列的cardinality來觀察。cardinality值表示索引中不重覆記錄數量的預估值。

那麼資料庫是怎麼樣來統計cardinality值的呢?cardinality值的統計是放在儲存引擎層的,因為不同的儲存引擎實現是不一樣的。還需要考慮的是索引的更新操作可能是非常頻繁的,每次索引操作都去統計會造成很大的壓力。如果一張表有很多的資料,那麼統計一次花費的時間也是比較長的。因此,innodb儲存引擎對cardinality的統計是通過取樣的方式進行的。

cardinality值發生在insert和update兩個操作中。但是不可能每次發生操作都去更新,更新的策略為:

第一種為自上次統計過之後,表中1/16的資料已發生過變化。第二種情況,儲存引擎內部有乙個計數器stat_modified_counter,用來表示發生變化的次數,當大於2000000000次數,也同樣需要更新cardinality資訊。

那麼cardinality值是怎麼更新的呢?同樣也是通過取樣的方式。預設對8個葉子節點進行取樣。具體過程如下:

取得索引中葉子節點的數量記為a

隨機取得索引中的8個葉子節點,統計每個頁不同記錄的個數,即為p1,p2......p8

根據取樣資訊算出預估值cardinality值=(p1+...+p8)*a/8

cardinality值是對8個葉子節點的資料預估得來的,所以一定不是準確值。因為其採用為隨機性,所以每次統計都有可能是不同的。可以通過引數innodb_stats_sample_pages來設定統計時取樣的數量。

那麼統計的時候對於null值怎麼處理的呢?預設為nulls_equal,即將null值記錄視為相等的記錄。該引數可以通過innodb_stats_method來修改,其有效值還有nulls_unequal,nulls_ignored,分別表示將null值視為不同的記錄和忽略null值記錄。

聯合索引是指對錶上的多個列進行索引。從本質上來說,聯合索引也是一顆b+樹,不同的是聯合索引的鍵值的數量不是1,而是大於等於2.鍵值是根據聯合的值進行排序的,也就是第乙個、第二個...因此,對於select * from table where a=*** and b=***會使用到(a,b)聯合索引。select * from table where  b=***則不會使用到,其滿足乙個最左匹配原則。

覆蓋索引也稱為索引覆蓋,即從輔助索引中就可以得到查詢的記錄,而不是需要查詢聚集索引中的記錄。使用覆蓋索引的好處是輔助索引不包含整行記錄的所有資訊,故其大小要遠小於聚集索引,因此可以大大減少io操作。另乙個好處是,統計類的查詢,innodb儲存引擎會盡量選擇輔助索引來統計。

注意:select * from table  where a=*** and b=*** 對於(a,b)的聯合索引會失效,這是因為查詢是* ,返回的結果中聯合索引只有a,b的值,滿足不了要求,所以優化器會選擇聚集索引來查資料。

mysql資料庫支援索引提示,可以顯式的告訴優化器使用哪個索引。例如:

select * from  table use index(a) where a=1 and b=2.對於a索引和(a,b)的聯合索引,雖然提示使用a索引了,但是mysql還是會選擇聯合索引。

select * from  table force index(a) where a=1 and b=2.此查詢會強制使用a索引

mysql5.6版本開始支援,multi-range read的目的是為了減少磁碟的隨機訪問,將隨機訪問轉換為較為順序的資料訪問。multi-range read優化適用於range,ref,eq_ref型別的查詢。

mrr優化有以下幾個好處

對於innodb和myisam儲存引擎的範圍查詢和join查詢操作,mrr的工作方式如下:

官方測試優化的效能還是比較大的,如下:

若使用了mrr特性,會在extra列顯示using mrr。

同時mrr還可以將某些範圍查詢,拆分為鍵值對,一次來進行批量的資料查詢。這樣的好處是,在拆分的過程中直接過濾一些不符合查詢條件的資料。例如:

select * from table where key1>=1000 and key1<2000 and key2=10000,此表有(key1,key2)的聯合索引

mrr啟用後,優化器會將查詢條件進行拆分為(1000,1000)(1001,1000)(1002,1000)...(1999,1000)進行查詢,不滿足的段直接過濾掉。

同樣為mysql5.6版本開始支援的索引查詢優化方式。傳統的查詢為根據索引來查詢記錄,然後再根據where條件來過濾。在支援該特性後,mysql會在取出索引的同時進行where條件的過濾,也就是將where的部分過濾操作放在了儲存引擎層。在某些查詢下,可以大大減少上層sql層對記錄的索取,從而提高資料庫的整體效能。

該優化支援range、ref、eq_ref、ref_or_null型別的查詢,當使用時,可在extra列看到using index condition提示。

MySQL系列之鎖

分布式鎖 疑問?什麼是共享鎖?共享鎖 共享讀鎖,排他鎖 獨佔寫鎖 鎖機制與innodb鎖演算法 在關係型資料庫中,可以按照鎖的粒度把資料庫鎖分為行級鎖 innodb引擎 表級鎖 myisam引擎 和頁級鎖 bdb引擎 myisam採用表級鎖 table level locking innodb支援行...

mysql學習之十 mysql編碼

mysql資料庫預設的編碼是 character set latin1 collation latin1 swedish ci檢視mysql支援的編碼 mysql show character set 檢視當前mysql伺服器預設編碼 mysql show variables like charac...

IT職場人生系列之十 創業觀

本文是it職場人生系列的第十篇。最近頭條是關於創業的,自己曾經想過很多,業來說兩句。本文不涉及如何創業,該在什麼行業創業的內容,只是從年齡的角度,看年輕人是否應該創業。沒有太多脈絡,從問題收入。最近就是創業的好時候。因為事業有成者所有錢都用來炒房子了,而年輕人則都變成了房奴,所以用來投資創業的資本銳...