數據庫性能系列之索引(中)

GOOD NIGHT

前言

上一篇中,我們已經了解到了索引的基本概念和一些用法。那索引為什么會提升查詢的速度,以及索引究竟是怎么工作的呢?也許大家心里還是有一些迷茫,這一切,還要從索引背后的算法說起。

GOOD NIGHT

概述

大家知道數據庫的索引和數據,一般都是存儲在硬盤中的,這樣利于數據的持久化和永久保存。因此在我們查找數據的時候,就會產生硬盤的I/O操作。而硬盤相較于內存而言,速度是比較慢的,所以如何減少硬盤的I/O操作,就是索引背后的算法存在的意義。

GOOD NIGHT

二分法

二分法是一種常用的查找算法,相較于逐個遍歷查找而言,二分法的時間復雜度為O(log2n)。為了幫助大家理解和回憶二分查找,我畫了一張二分查找的流程圖:

4348dadf73dd83418df1f5a6cd8ca8d1.png

從上述流程來看,我們要事先對要查找的數組或集合進行排序,而且每次會尋找中間節點進行范圍的劃分和對數字的比較。那么我們能不能把這個過程進行簡化呢?二叉搜索樹(Binary Search Tree)會給你答案。

GOOD NIGHT

二叉搜索樹

如上文所述,二叉搜索樹的特征是有序,且預先把數據進行分段存儲,并且將中間節點作為樹的根節點,那么我們會得到如下的二叉樹結構,這里以數組[7,25,36,50,64,78,87]為例,創建出來的二叉樹如下所示:

fe10da540d43b57d9918fd47496de697.png

我們可以看出一些特征:對于每個節點而言,它的左孩子都小于它的父節點,而右孩子,都大于它的父節點。所以我們把這樣的二叉樹,叫做二叉搜索樹(Binary Search Tree)。

二叉搜索樹,重復利用了二分法的思想來查找數據,但有時由于構造樹時產生問題,導致同樣的數據插入順序不一樣,二叉搜索樹就會變成如下結構:

e4b625f70f1a117bd549c4a2e99077ae.png

從兩張圖的比較中我們不難看出,圖一的樹高度為3,也就是最多只需要3次比較,就能找出節點,而圖二的樹的結構會變成線性,需要7次比較,查找時的復雜度也會瞬間提升為O(n)。

所以為了解決二叉樹不平衡的問題,人們又提出了新的數據結構,叫做平衡二叉搜索樹(AVL樹)

GOOD NIGHT

平衡二叉搜索樹

剛才我們提出了,要解決二叉樹的不平衡問題,就需要一個可以在每次插入或者刪除節點時,都可以做到自動平衡的二叉樹結構,也叫平衡二叉搜索樹。

平衡二叉搜索樹的核心思想就是計算每個節點的平衡因子(balance factor),平衡因子的定義是一個節點的左孩子的高度減去其右孩子的高度,這里的高度(height)就是指從一個節點出發到達最遠葉子節點所經過的最長路徑。如我們上述的圖一中,從根節點50,到達子節點36的高度即為2。

通過上面的概念,我們可以發現,當一個節點的平衡因子絕對值大于等于1時,樹就不再平衡,所以這里平衡二叉樹還包含了一個旋轉的機制,在此不表,感興趣的同學可以自行查找進行理解。

那么我們在講了這么多之后,平衡二叉搜索樹是不是就可以作為索引背后的數據結構來進行存儲了呢?這里再使用一張圖來直觀說明一下:

6f616a343ce6fb9641687539ed763a39.png

我們前文提到了查找數據是走了硬盤的I/O操作,那么對于這棵二叉樹來說,樹的高度為5,最壞的情況下,需要查找5次。這就意味著,如果樹的高度越高,那么硬盤的I/O次數也會越多。

所以我們有沒有辦法去降低樹的高度呢?可以遵循這樣的思路去思考,如果一個節點下不止2個子節點,而是多個,那么整體的高度就可以降低。比如我們將二叉樹,改為三叉樹:

c748407dabf96980caf2a64496c35d52.png

這個時候,同樣的節點數量,我們的樹高度則降為了4,也就是說,最多需要4次I/O即可找到需要查找的內容。

所以我們可以將二叉樹改為M叉樹(M>2),即一個節點下有M個子節點,這樣當數據量大小為N時,M叉樹的高度將會遠遠小于二叉樹的高度,這樣就引申出了B樹的概念。

GOOD NIGHT

什么是B樹?

B樹的英文全名為Banlance Tree,翻譯過來為平衡多路搜索樹,我們從上文中已知,當一個節點有多個子節點時,高度會下降,因此B樹很適合用于查詢,在文件系統和數據庫系統中的索引,常常會使用B樹來實現。在這里有一個概念糾正下,有些書中或博客會提到B-樹,而實際上B-樹和B樹是同一種結構,只是翻譯名稱上存在一些誤解。

B樹的結構如圖所示:

6dd3b154f109253060323cccb36871e4.png

B 樹作為平衡的多路搜索樹,它的每一個節點最多可以包括 M 個子節點,M 稱為 B 樹的階。每個節點中,都存儲了關鍵字和子節點的指針。對于一個 100 階的 B 樹來說,如果有 3 層的話最多可以存儲約 100*100* 100=100 萬的索引數據。

B樹的特性有以下幾點:

1、所有節點關鍵字是按遞增次序排列,并遵循左小右大原則。

2、樹中的每個節點至多有M個子節點,即至多有M-1個關鍵字(二叉樹有2個子節點和1個關鍵字)。

3、除根節點外,其他節點至少有M/2個子節點。

4、若根節點不是葉子節點,則根節點至少有2個子節點。

5、所有葉子節點均在同一層,所以B樹是一個所有平衡因子均為0的多路查找樹。

以上圖為例,根節點中有2個關鍵字:17和35,以及3個子節點指針:P1、P2和P3。而且在第二層最左側的子節點中,有2個關鍵字8和12,包含了3個子節點。子節點1中的關鍵字為3和5,都小于8,而子節點2中的關鍵字為9和10,大于8小于12,子節點3中的關鍵字為13和15,均大于12,都符合我們上述提到的特性。

如果我們使用B樹進行查找關鍵字9,那么可以分為以下幾步:

1、先與根節點進行比較,9小于17,那么我們可以得到指針P1,繼續從子節點中進行查找;

2、在子節點中,9大于8而小于12,此時可以得到指針P2,繼續往下查找;

3、在最后一層的子節點中,找出關鍵字9,結束查找。

可以看出,相較于平衡二叉樹而言,B樹查找時的磁盤I/O要少,整體查詢效率也要高出很多。看到這里相信大家已經大致明白了索引背后的工作原理,B樹已經很適合作為索引的算法。但實際上,在MySQL中,還會使用B+樹索引,這又是為什么呢?

GOOD NIGHT

B+樹的改進

相較于B樹而言,B+樹在兩個方面又做出了改進和提升,一方面是查詢的穩定性,另一方面是查詢的效率更高。

B+樹的結構如下圖所示:

b41f0ebeaca20f4cad8b3e13e17c437f.png

與B樹相比,B+樹的非葉子節點不保存具體的數據,而只保存關鍵字的索引,所有的數據都會保存至葉子節點。因為所有數據必須要到葉子節點才能獲取到,所以每次數據查詢的次數都一樣,這樣一來B+樹的查詢速度也就會比較穩定。

在B+樹中,非葉子節點的子節點數=關鍵字數,如上圖所示,根節點有2個關鍵字,對于的也有2個子節點。這樣的好處是一個節點可以存儲更多的關鍵字,階數會更大,高度會更低,查詢效率也就更高。

B+樹查找關鍵字的方式與B樹類似,先從關鍵字中找出范圍和指針,然后找到對應的子節點,一級一級往下查詢,直到最終的葉子節點查出所需要的數據。

由于B+樹的數據都存儲在葉子節點,所以更有利于數據庫做全表掃描,不需要像B樹一樣逐層掃描,而是直接遍歷所有的葉子節點即可。

GOOD NIGHT

總結

今天我們從最基本的二分查找開始,逐步分析了各種查找樹的工作原理和優缺點,不斷改進,從而挖掘出最終的B樹和B+樹算法,深刻理解了索引背后的工作原理。雖然傳統的二叉樹查詢的效率也很高,但是很容易增加磁盤I/O的次數,影響索引使用的效率,所以我們最終會采用降低樹高度的方式來構造索引。

在實際工作中,我們使用索引也許不會直接去編寫B樹和B+樹的算法。但是學習這些算法,會有助于我們增強邏輯思考的能力,還可以提升一些設計方面的能力,對于“修煉內功”會很有幫助,希望大家可以在這條路上持之以恒。

下一期將是索引系列的最終篇章,我們會結合實際工作中的復雜SQL場景,合理使用索引和改寫原有語句以避免全表掃描來對數據庫進行優化,敬請期待!

47002dcda9476a3d3e64ce019ef5ed69.png

您的點贊和在看是我創作的最大動力,感謝支持

b19aeaa59133bbf240d9f6bc99eb2316.jpeg

7d37dac3b57346cfbf66e81f2e984ec7.png

8dd831b914580f994e6a3cd82075d9f9.png

公眾號:wacky的碎碎念

知乎:wacky

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/284130.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/284130.shtml
英文地址,請注明出處:http://en.pswp.cn/news/284130.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

微服務架構的設計原則和核心話題

目錄 一、前言 二、微服務架構的設計原則 1.拆分足夠微 2.輕量級通信 3.單一職責原則 4.領域驅動原則 三、微服務架構的核心話題 1.服務拆分 2.服務注冊與發現 3.負載均衡 4.API網關 5.服務部署與發布 四、總結 一、前言 毫無疑問,微服務架構的設計原…

4.3.2 基于集合的操作

在SQL Server處理select命令時,會在內存中建立一個結構,以返回結果集。這個結構實質上是一個有行和列的二維數組,稱為“游標(cursor)”。“游標”這個詞是“CURrent set of Records(當前記錄集)”的縮寫。它表示從表或…

Golang GOPATH 包

2019獨角獸企業重金招聘Python工程師標準>>> Golang GOPATH & 包的定義 & 包的導入 GOPATH 設置 go 命令依賴一個重要的環境變量:$GOPATH 可以在 .zshrc 配置文件中加上一行這樣的配置, export GOPATH/Users/flyme/mygo Go從1.1版本到…

PPK大疆無人機應用教程

文章目錄 一、新建項目二、導入數據三、解算過程四、結果導出一、新建項目 新建工程,設置項目名稱,保存位置,控制等級,坐標系統(坐標系統選擇高斯克呂格,中央子午線根據實際數據所在位置進行選擇) 二、導入數據 選擇大疆數據,找到對應的文件夾 數據有:圖片,EVENT.b…

Eclipse Add generated serial version ID報錯解決方案

為什么80%的碼農都做不了架構師?>>> 問題: The following problem occurred:Could not find class file.Make sure the file is compilable 解決方案: 1、右鍵項目 -> Java Build Path -> Source 在Sourcd folders on bui…

開啟線程的方式

1、實現Runnable接口 1 package test;2 3 4 5 public class ThreadTest implements Runnable{6 public void tt(){7 Thread t new Thread(this);8 t.start();9 } 10 11 Override 12 public void run() { 13 while(true){ 14 …

C# WPF設備監控軟件(經典)-上篇

01—前言應老東家也是老同學的需求,開發了此設備監控軟件。主要是為了應對測試設備長時間不上傳測試數據未能及時發現的問題,測試數據一般在每臺設備都有個固定的臨時存放目錄,測試數據不更新時,此文件夾便不再更新。需求相對比較…

[轉]微服務的4個設計原則和19個解決方案

目錄 一、微服務架構演進過程 二、微服務架構的好處 三、微服務應用4個設計原則 1.AKF拆分原則 2.前后端分離 3.無狀態服務 4.Restful通信風格 四、微服務架構帶來的問題 五、微服務平臺的19個落地實踐 1.企業IT建設的三大基礎環境 2.微服務應用平臺總體架構 3.微服…

時間處理總結(二)oracle

不斷總結中................. 1.等于land.djsjto_date(2016/7/26,yyyy-MM-dd)2.大于等于land.djsj>to_date(2016/7/26,yyyy-MM-dd)3.小于等于land.djsj<to_date(2016/7/26,yyyy-MM-dd)4.區間land.djsj>to_date(2016/7/26,yyyy-MM-dd) and land.djsj<to_date(2016/7…

【GlobalMapper精品教程】033:影像地圖羽化方式詳解

在Globalmapper中,可以很方便的對影響進行多種羽化值設置。 文章目錄 1. 不要羽化此圖層2. 沿一個或多個邊緣羽化3. 羽化到有效數據的多邊形覆蓋4. 在當前選定的多邊形內羽化5. 裁剪到選定的邊界,而不是羽化6. 在多邊形外部羽化,而不是內部加載配套案例數據包中的data033.ra…

基于WPF重復造輪子,寫一款數據庫文檔管理工具(一)

項目背景公司業務歷史悠久且復雜&#xff0c;數據庫的表更是多而繁雜&#xff0c;每次基于老業務做功能開發都需要去翻以前的表和業務代碼。需要理解舊的表的用途以及包含的字段的含義&#xff0c;表少還好說&#xff0c;但是表一多這就很浪費時間&#xff0c;而且留下來的文檔…

[轉]GitBook使用教程收藏

GitBook使用教程 最簡單的方式就是使用GitBook編輯器&#xff0c;沒有什么難度&#xff0c;后面的教程主要針對命令行的方式 PS&#xff1a;GitBook的book頁面默認沒有download按鈕的 需要到設置中打開&#xff0c;打開后再次publish生效 同步GitHub 更新失敗&#xff0c;無法…

二 面向對象三大特性

一 繼承與派生 一、繼承定義 二、繼承與抽象的關系 三、繼承與重用性 四、派生 五、組合與重用性 六、接口與歸一化設計 七、抽象類 八、繼承實現的原理 九、子類中調用父類的方法 二 多態與多態性 一、多態 二、多態性 三 封裝 一、封裝定義 二、特性(property) 三、封裝與擴展…

CSS3新屬性

邊框&#xff1a; border-radius 用于創建圓角 div { border:2px solid; border-radius:25px; -moz-border-radius:25px; /* Old Firefox */ } box-shadow 用于向方框添加陰影 div { box-shadow: 10px 10px 5px #888888; } border-image 使用圖片來創建邊框 div { border-image…

Android實用筆記——使用Spinner實現下拉列表

2019獨角獸企業重金招聘Python工程師標準>>> 1、編輯activity_main.xml <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"mat…

基于.NET 6 的開源訪客管理系統

簡單介紹一下系統功能系統用于簡化訪客登記、查詢、保存。傳統的登記方式&#xff0c;不僅浪費紙張&#xff0c;而且還面臨保存的問題&#xff0c;查閱不方便。該系統為了在疫情期間能很好管理訪客登記做好風險管控,同時可以整合智能設備做到自動確認并跟蹤訪客的行動軌跡,該項…

完整的產品管理工作流程

產品經理的工作具體會落實到工作流程中&#xff0c;所以工作流程很大程度上會體現工作層次。很多白領產品經理&#xff0c;多年來在一個低層次的流程中轉圈——理需求、畫原型、寫文檔、管項目、驗收上線&#xff0c;一個版本上線之后立刻對下一個版本理需求、畫原型、寫文檔、…

java爬蟲-簡單爬取網頁圖片

剛剛接觸到“爬蟲”這個詞的時候是在大一&#xff0c;那時候什么都不明白&#xff0c;但知道了百度、谷歌他們的搜索引擎就是個爬蟲。 現在大二。再次燃起對爬蟲的熱愛&#xff0c;查閱資料&#xff0c;知道常用java、python語言編程&#xff0c;這次我選擇了java。在網上查找的…

擴展方法必須在非泛型靜態類中定義

擴展方法必須在非泛型靜態類中定義&#xff1a;public class CustomerHelperClass{public static MvcHtmlString CreateImage(string p_w_picpathSource, string altText, string width, string height){//通過TagBulider創建標簽TagBuilder p_w_picpathTag new TagBuilder(&…

Windows Server 2016-圖形化遷移FSMO角色

上章節我們簡單介紹了三種不同方式查看FSMO主機角色信息&#xff0c;在開篇之前我們簡單回顧一下FSMO五種操作主機角色&#xff1a;林范圍操作主機角色有兩種&#xff0c;分別是 架構主機角色&#xff08;Schema Master&#xff09;和 域命名主機角色&#xff08;Domain Naming…