數據庫索引《一》

目錄

索引的類型  

回表

索引維護

思考與解答


   索引是存儲引擎實現的,沒有統一的標準,不同的引擎的索引工作方式不一樣。常見的三種索引結構:哈希表/有序數組/搜索樹。

哈希表

數據結構:數組+鏈表的方式;

優點:等值查詢的速度比較快; 

缺點:因爲無序,做區間查詢比較慢,時間複雜度O(N);

適用場景:membercache和noslq等一些存儲引擎;                                                  

有序數組

數據結構:數組;

優點:查找和範圍查找效率高,二分查找,時間複雜度:O(logN);

缺點:更新數據成本較高,效率低下;

適用場景:靜態存儲引擎[不需要修改的數據];

N叉樹

數據結構: N叉樹;

優點:查找和更新的複雜度可以維持在O(logN);

 

跳錶 二叉樹的原理,“拋硬幣法提升一層”
LSM樹 LSM 通過將磁盤的隨機寫轉化爲順序寫來提高寫性能 ,而付出的代價就是犧牲部分讀性能、寫放大(B+樹同樣有寫放大的問題)。LSM 相比 B+ 樹能提高寫性能的本質原因是:外存——無論磁盤還是 SSD,其隨機讀寫都要慢於順序讀寫

索引的類型  

     我們直到MySql裏的默認存儲引擎是InnoDB,InnoDB使用了B+樹索引模型,所以數據都是存儲在B+樹中。每一個索引在InnoDB裏面對應一棵B+樹,每張表由多棵B+樹組成。
索引類型分爲:主鍵索引和非主鍵索引。
  主鍵索引的葉子節點存的都是整行數據。在InnoDB,主鍵索引也稱爲聚簇索引(clustered index);
  非主鍵索引的葉子節點內容是主鍵的值。在InnoDB裏,非主鍵索引也被稱爲二級索引(secondary index);
 下面通過一個實例來具體分析下索引的結構以及是如何工作的。

USER_TABLE | CREATE TABLE `USER_TABLE` (
  `id` int(11) NOT NULL,
  `age` int(11) NOT NULL,
  `orderId` bigint DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `orderId` (`orderId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

//插入數據
insert into students (id, age, orderId) values (1,18,101),(2,19,102),(3,20,103),(4,21,104),(5,22,105);

假設給這張表插入5行數據(id,age,orderId):(1,18,101),(2,19,102),(3,20,103),(4,21,104),(5,22,105)。假設該表的索引是一棵4叉樹。

圖一:4叉樹索引圖

回表

下面來看一下:主鍵索引和普通索引的區別

select * from USER_TABLE where id = 2; 

   主鍵索引及主鍵查詢方式,我們只需要搜索id這棵B+樹,查到的就是整個id=2的行記錄; 

select * from USER_TABLE where orderId = 102;

   普通索引查詢,我們需要先查詢orderId 二級索引,得到id=1,然後再搜索主鍵索引得到行記錄,這裏可以看到,我們進行來兩次查詢,這個過程叫做回表。所以很明顯,主鍵索引只需要搜索一次就可以拿到數據。普通索引先搜索索引拿到主鍵,然後再到主鍵索引搜索一次纔可以拿到這個值(回表)。我們在實際使用過程中,儘量使用主鍵索引減少查詢次數,提高效率

索引維護

    我們知道B+樹在構造的過程中當某個分支的節點數大於N的時候存在分裂和合並的過程。這裏涉及到數據的增加和刪除,其中增加節點過程中的分頁:將會影響性能空間利用率下降,因爲需要移動一半的數據到一個新的空間。
    從上面我們可以看出主鍵索引的重要性,那麼自增主鍵做索引的好處是什麼呢?
 性能方面
     一般插入新紀錄的時候,我們不需要指定id的值,系統會獲取當前的最大的id自增後作爲下一條記錄id的值。這樣的好處是:構造B+ 樹過程中,不需要移動大量的數據,不涉及到葉子節點的分裂,性能較高。不是有序的節點的插入往往成本較高。主要的是通過主鍵做索引無需回表查詢,減少磁盤訪問次數,提高效率
存儲空間
     主鍵一般都是整型數據,只需要4個字節,如果是長整型需要8個字節。但是如果是業務字段做索引,比如訂單號或者省份證號都會比主鍵大,而主鍵是二級索引的值,所以二級索引就會佔用更大的空間。
    顯然主鍵越小,普通的索引的葉子節點就越小,佔用的空間就越小。

   總體來說,我們需要“儘量使用主鍵來查詢”的原則,避免搜索兩棵樹。

    當然在KV存儲場景中:只有一個索引且必須唯一,這個時候使用業務字段直接做主鍵是十分合適的。

 

思考與解答

問題一:爲什麼不使用二叉樹,要使用N叉樹?

答:雖然平衡二叉樹的搜索和更新效率很高,但是大多數的數據庫並不是採用的二叉樹,這是因爲索引不只是存在內存中,還要寫到磁盤上。僅僅對於1024個數據節點,二叉樹的樹高達到了10,那麼一次查詢就需要查詢10個數據塊。從磁盤隨機讀取一個數據塊的時間大概是20ms,所以這個時間是200ms,這個速度是很慢的。爲了提高查詢的速度,訪問儘量少的數據塊,我們採用了“N叉樹”讓樹的高度降下來。這樣就減少了訪文磁盤的次數及時間。例如一個整數字段的索引,n差不多是1200,對於3層高的樹,其能容納的值爲 17億,也就是說尋找一個數據最多隻需要訪問3次磁盤。由於N叉樹很好的讀寫性能優勢,以及適配磁盤的訪問模式,已經被廣泛的應用到數據庫引擎中了。

磁盤尋址過程:每次訪問磁盤的一個塊時,磁臂就需移動到正確的磁道上(這段時間爲尋址時間),然後盤片就需旋轉到正確的扇區上(這叫旋轉時延),這套動作需要時間,所以說順序寫比隨機寫性能高,大部分情況db的最大瓶頸在io;

問題二:B+樹的缺點

答:(1) 插入可能會引起數據頁的分裂;(2) 刪除可能會引起數據頁的合併。二者都是比較重的io消耗。所以比較好的方式是順序插入,這也是我們選擇自增主鍵的原因。

問題三:N叉樹的n能調整嗎?

 答:樹高取決於葉子樹(數據行數) 和”N叉樹”的N。而N又是頁大小和索引大小決定的。

     磁盤讀取數據是以磁盤塊爲基本單位的(1 Block = 4KB),也即是每次最少讀4KB,內存頁的大小是4KB。爲了達到最大性能,B+Tree 的每個節點的大小就是塊的大小(4KB),這樣每個節點可以一次性全部讀到內存,減少磁盤 io 次數。由於節點中只存儲 key 和 point。

假設有 n 個 key,那麼就有n+1 個point:
32位系統中,int 類型佔4個字節,指針佔4個字節,則有:4n+4*(n+1)<=4096  n=511。
64位系統中,int 類型佔4個字節,指針佔8個字節,則有:4n+8*(n+1) <= 4096n = 170;
大概值:32位系統中,B+Tree 的度爲512,64位系統中,B+Tree 的度171。
如果 MySQL 的 B+Tree 結構中除了必備的 key 和 point,還有其他結構的話,度會相應減少。

問題4:重建索引需要注意什麼?

   二叉樹的高度對sql的查詢起着一定的影響,另外當數據插入的時候,可能會產生分頁,存儲空間利用率低,刪除的數據也會導致碎片空間,這時候就需要重建優化索引,一般情況很少去優化或者是重建。
   如果是主鍵索引,無論是刪除還是重建主鍵索引,都會將整個表重建,並且會使所有的二級索引失效,並且會用ROWID來做主鍵索引。當需要刪除和重建普通索引的時候,就只需要刪除該普通索引即可,正常來說沒有影響。
重建索引的方式:
(1) 離線的業務:整個數據庫遷移,先dump出來再重建表;
(2) 使用alter操作:ALTER TABLE TABLE ENGIN=InnoDB;這個命令回原地重建表結構;
(3) 使用repair table,這個取決於存儲引擎是否支持;

 

學習筆記,內容簡單,用於複習,原內容2月有更新。
##參考資料,《MySql實戰詳解》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章