1. 程式人生 > >資料庫兩大必備神器:索引和鎖底層原理是什麼!

資料庫兩大必備神器:索引和鎖底層原理是什麼!

一、索引

在之前,我對索引有以下的認知:

索引可以加快資料庫的檢索速度;

表經常進行INSERT/UPDATE/DELETE操作就不要建立索引了,換言之:索引會降低插入、刪除、修改等維護任務的速度;

索引需要佔物理和資料空間;

瞭解過索引的最左匹配原則;

知道索引的分類:聚集索引和非聚集索引;

Mysql支援Hash索引和B+樹索引兩種;

看起來好像啥都知道,但面試讓你說的時候可能就GG了:

使用索引為什麼可以加快資料庫的檢索速度啊?

為什麼說索引會降低插入、刪除、修改等維護任務的速度;

索引的最左匹配原則指的是什麼?

Hash索引和B+樹索引有什麼區別?主流的使用哪一個比較多?InnoDB儲存都支援嗎?

聚集索引和非聚集索引有什麼區別?

........

1、聊聊索引的基礎知識

首先Mysql的基本儲存結構是頁(記錄都存在頁裡邊):

各個資料頁可以組成一個雙向連結串列;

而每個資料頁中的記錄又可以組成一個單向連結串列;

每個資料頁都會為儲存在它裡邊兒的記錄生成一個頁目錄,在通過主鍵查詢某條記錄的時候可以在頁目錄中使用二分法快速定位到對應的槽,然後再遍歷該槽對應分組中的記錄即可快速找到指定的記錄;

以其他列(非主鍵)作為搜尋條件:只能從最小記錄開始依次遍歷單鏈表中的每條記錄。

所以說,如果我們寫select * from user where username = 'Java3y'這樣沒有進行任何優化的sql語句,預設會這樣做:

定位到記錄所在的頁

需要遍歷雙向連結串列,找到所在的頁

從所在的頁內中查詢相應的記錄

由於不是根據主鍵查詢,只能遍歷所在頁的單鏈表了

很明顯,在資料量很大的情況下這樣查詢會很慢!

2、索引提高檢索速度

索引做了些什麼可以讓我們查詢加快速度呢?

其實就是將無序的資料變成有序(相對):

要找到id為8的記錄簡要步驟:

很明顯的是:沒有用索引我們是需要遍歷雙向連結串列來定位對應的頁,現在通過"目錄"就可以很快地定位到對應的頁上了!

其實底層結構就是B+樹,B+樹作為樹的一種實現,能夠讓我們很快地查找出對應的記錄。

3、索引降低增刪改的速度

如果一棵普通的樹在極端的情況下,是能退化成連結串列的(樹的優點就不復存在了)

B+樹是平衡樹的一種,是不會退化成連結串列的,樹的高度都是相對比較低的(基本符合矮矮胖胖(均衡)的結構)【這樣一來我們檢索的時間複雜度就是O(logn)】!從上一節的圖我們也可以看見,建立索引實際上就是建立一顆B+樹。

B+樹是一顆平衡樹,如果我們對這顆樹增刪改的話,那肯定會破壞它的原有結構;

要維持平衡樹,就必須做額外的工作。正因為這些額外的工作開銷,導致索引會降低增刪改的速度;

4、雜湊索引

除了B+樹之外,還有一種常見的是雜湊索引。

雜湊索引就是採用一定的雜湊演算法,把鍵值換算成新的雜湊值,檢索時不需要類似B+樹那樣從根節點到葉子節點逐級查詢,只需一次雜湊演算法即可立刻定位到相應的位置,速度非常快。

本質上就是把鍵值換算成新的雜湊值,根據這個雜湊值來定位。

看起來雜湊索引很牛逼啊,但其實雜湊索引有好幾個侷限(根據他本質的原理可得):

雜湊索引也沒辦法利用索引完成排序;

不支援最左匹配原則;

在有大量重複鍵值情況下,雜湊索引的效率也是極低的---->雜湊碰撞問題;

不支援範圍查詢;

5、InnoDB支援雜湊索引嗎?

主流的還是使用B+樹索引比較多,對於雜湊索引,InnoDB是自適應雜湊索引的(hash索引的建立由InnoDB儲存引擎引擎自動優化建立,我們干預不了)!

6、聚集和非聚集索引

簡單概括:

聚集索引就是以主鍵建立的索引;

非聚集索引就是以非主鍵建立的索引;

區別:

聚集索引在葉子節點儲存的是表中的資料;

非聚集索引在葉子節點儲存的是主鍵和索引列;

使用非聚集索引查詢出資料時,拿到葉子上的主鍵再去查到想要查詢的資料。(拿到主鍵再查詢這個過程叫做回表)

非聚集索引也叫做二級索引,不用糾結那麼多名詞,將其等價就行了~

非聚集索引在建立的時候也未必是單列的,可以多個列來建立索引。

此時就涉及到了哪個列會走索引,哪個列不走索引的問題了(最左匹配原則-->後面有說)

建立多個單列(非聚集)索引的時候,會生成多個索引樹(所以過多建立索引會佔用磁碟空間)

在建立多列索引中也涉及到了一種特殊的索引-->覆蓋索引

我們前面知道了,如果不是聚集索引,葉子節點儲存的是主鍵+列值

最終還是要“回表”,也就是要通過主鍵再查詢一次。這樣就會比較慢

覆蓋索引就是把要查詢出的列和索引是對應的,不做回表操作!

比如說:

現在我建立了索引(username,age),在查詢資料的時候:select username , age from user where username = 'Java3y' and age = 20。

很明顯地知道,我們上邊的查詢是走索引的,並且,要查詢出的列在葉子節點都存在!所以,就不用回表了~

所以,能使用覆蓋索引就儘量使用吧~

7、索引最左匹配原則

最左匹配原則:

索引可以簡單如一個列(a),也可以複雜如多個列(a, b, c, d),即聯合索引。

如果是聯合索引,那麼key也由多個列組成,同時,索引只能用於查詢key是否存在(相等),遇到範圍查詢(>、<、between、like左匹配)等就不能進一步匹配了,後續退化為線性查詢。

因此,列的排列順序決定了可命中索引的列數。

例子:

如有索引(a, b, c, d),查詢條件a = 1 and b = 2 and c > 3 and d = 4,則會在每個節點依次命中a、b、c,無法命中d。(很簡單:索引命中只能是相等的情況,不能是範圍匹配)

8、=、in自動優化順序

不需要考慮=、in等的順序,mysql會自動優化這些條件的順序,以匹配儘可能多的索引列。

例子:

如有索引(a, b, c, d),查詢條件c > 3 and b = 2 and a = 1 and d < 4與a = 1 and c > 3 and b = 2 and d < 4等順序都是可以的,MySQL會自動優化為a = 1 and b = 2 and c > 3 and d < 4,依次命中a、b、c。

9、索引總結

索引在資料庫中是一個非常重要的知識點!上面談的其實就是索引最基本的東西,要創建出好的索引要顧及到很多的方面:

1,最左字首匹配原則。這是非常重要、非常重要、非常重要(重要的事情說三遍)的原則,MySQL會一直向右匹配直到遇到範圍查詢(>,<,BETWEEN,LIKE)就停止匹配。

3,儘量選擇區分度高的列作為索引,區分度的公式是 COUNT(DISTINCT col) / COUNT(*)。表示欄位不重複的比率,比率越大我們掃描的記錄數就越少。

4,索引列不能參與計算,儘量保持列“乾淨”。比如,FROM_UNIXTIME(create_time) = '2016-06-06' 就不能使用索引,原因很簡單,B+樹中儲存的都是資料表中的欄位值,但是進行檢索時,需要把所有元素都應用函式才能比較,顯然這樣的代價太大。所以語句要寫成 : create_time = UNIX_TIMESTAMP('2016-06-06')。

5,儘可能的擴充套件索引,不要新建立索引。比如表中已經有了a的索引,現在要加(a,b)的索引,那麼只需要修改原來的索引即可。

6,單個多列組合索引和多個單列索引的檢索查詢效果不同,因為在執行SQL時,MySQL只能使用一個索引,會從多個單列索引中選擇一個限制最為嚴格的索引。

二、鎖

在mysql中的鎖看起來是很複雜的,因為有一大堆的東西和名詞:排它鎖,共享鎖,表鎖,頁鎖,間隙鎖,意向排它鎖,意向共享鎖,行鎖,讀鎖,寫鎖,樂觀鎖,悲觀鎖,死鎖。這些名詞有的部落格又直接寫鎖的英文的簡寫--->X鎖,S鎖,IS鎖,IX鎖,MMVC...

鎖的相關知識又跟儲存引擎,索引,事務的隔離級別都是關聯的....

這就給初學資料庫鎖的人帶來不少的麻煩~~~於是我下面就簡單整理一下資料庫鎖的知識點,希望大家看完會有所幫助。

1、為什麼需要學習資料庫鎖知識

不少人在開發的時候,應該很少會注意到這些鎖的問題,也很少會給程式加鎖(除了庫存這些對數量準確性要求極高的情況下)

一般也就聽過常說的樂觀鎖和悲觀鎖,瞭解過基本的含義之後就沒了~~~

定心丸:即使我們不會這些鎖知識,我們的程式在一般情況下還是可以跑得好好的。因為這些鎖資料庫隱式幫我們加了:

對於UPDATE、DELETE、INSERT語句,InnoDB會自動給涉及資料集加排他鎖(X);

MyISAM在執行查詢語句SELECT前,會自動給涉及的所有表加讀鎖,在執行更新操作(UPDATE、DELETE、INSERT等)前,會自動給涉及的表加寫鎖,這個過程並不需要使用者干預;

只會在某些特定的場景下才需要手動加鎖,學習資料庫鎖知識就是為了:

能讓我們在特定的場景下派得上用場

更好把控自己寫的程式

在跟別人聊資料庫技術的時候可以搭上幾句話

構建自己的知識庫體系!在面試的時候不虛

2、表鎖簡單介紹

首先,從鎖的粒度,我們可以分成兩大類:

表鎖開銷小,加鎖快;不會出現死鎖;鎖定力度大,發生鎖衝突概率高,併發度最低;

行鎖開銷大,加鎖慢;會出現死鎖;鎖定粒度小,發生鎖衝突的概率低,併發度高;

不同的儲存引擎支援的鎖粒度是不一樣的:

InnoDB行鎖和表鎖都支援!

MyISAM只支援表鎖!

InnoDB只有通過索引條件檢索資料才使用行級鎖,否則,InnoDB將使用表鎖

也就是說,InnoDB的行鎖是基於索引的!

表鎖下又分為兩種模式:

表讀鎖(Table Read Lock)

表寫鎖(Table Write Lock)

從下圖可以清晰看到,在表讀鎖和表寫鎖的環境下:讀讀不阻塞,讀寫阻塞,寫寫阻塞!

讀讀不阻塞:當前使用者在讀資料,其他的使用者也在讀資料,不會加鎖

讀寫阻塞:當前使用者在讀資料,其他的使用者不能修改當前使用者讀的資料,會加鎖!

寫寫阻塞:當前使用者在修改資料,其他的使用者不能修改當前使用者正在修改的資料,會加鎖!

從上面已經看到了:讀鎖和寫鎖是互斥的,讀寫操作是序列。

如果某個程序想要獲取讀鎖,同時另外一個程序想要獲取寫鎖。在mysql裡邊,寫鎖是優先於讀鎖的!

寫鎖和讀鎖優先順序的問題是可以通過引數調節的:max_write_lock_count和low-priority-updates

值得注意的是:

MyISAM可以支援查詢和插入操作的併發進行。可以通過系統變數concurrent_insert來指定哪種模式,在MyISAM中它預設是:如果MyISAM表中沒有空洞(即表的中間沒有被刪除的行),MyISAM允許在一個程序讀表的同時,另一個程序從表尾插入記錄。

但是InnoDB儲存引擎是不支援的!

3、樂觀鎖和悲觀鎖

無論是Read committed還是Repeatable read隔離級別,都是為了解決讀寫衝突的問題。

單純在Repeatable read隔離級別下我們來考慮一個問題:

此時,使用者李四的操作就丟失掉了:

丟失更新:一個事務的更新覆蓋了其它事務的更新結果。

(ps:暫時沒有想到比較好的例子來說明更新丟失的問題,雖然上面的例子也是更新丟失,但一定程度上是可接受的..不知道有沒有人能想到不可接受的更新丟失例子呢...)

解決的方法:

使用Serializable隔離級別,事務是序列執行的!

相關推薦

資料庫必備神器索引底層原理是什麼

一、索引 在之前,我對索引有以下的認知: 索引可以加快資料庫的檢索速度; 表經常進行INSERT/UPDATE/DELETE操作就不要建立索引了,換言之:索引會降低插入、刪除、修改等維護任務的速度; 索引需要佔物理和資料空間; 瞭解過索引的最左匹配原則; 知道索引的分類:聚集索引和非聚集索引;

資料庫神器索引

前言 只有光頭才能變強 索引和鎖在資料庫中可以說是非常重要的知識點了,在面試中也會經常會被問到的。 本文力求簡單講清每個知識點,希望大家看完能有所收穫 宣告:如果沒有說明具體的資料庫和儲存引擎,預設指的是MySQL中的InnoDB儲存引擎 一、索引 在之前,我

spring中的核心模組IOCAOP

Spring就像一個管家,幫你管理事務。傳統的應用,應用層(Struts2)和事務層(Service)聯絡很緊密,通過Spring管理之間的關係,減低其耦合性。Spring的出現就是為了解決現有問題,使開發更快捷,更健壯。另外,一定要好好學習Spring,他可是有一統天下的野心。有針對Stru

立足於存證溯源應用場景他們想利用區塊鏈技術顛覆現有供應鏈金融模式

本堂茜 渡鴉區塊鏈專欄記者 信數鏈CEO王大偉上海交通大學高階金融學院MBA畢業,職業生涯分別就職於盛大,IBM,攜程。2015年從攜程離職,開始自己的第一次創業之

SaltStack遠程執行模塊cmd與cp模塊測試

SaltStack cp.get_file cp.push cmd.run cmd.script 上一篇分享了《SaltStack安裝配置與遠程執行測試》,涉及到了test.ping和cmd.run兩個模塊方法,實際上SaltStack的模塊有140多個之多,每個模塊又有多種函數(func

599. Minimum Index Sum of Two Lists個餐廳列表的索引最小

ins 條件 ner 模板 還要 order PE ioc form [抄題]: Suppose Andy and Doris want to choose a restaurant for dinner, and they both have a list of favo

深入理解Spring的特征(IOCAOP)<轉>

編譯器 如果 定義 包括 其他 enc row 這就是 生命 在某博主的博客上看到一篇解釋Spring的兩大核心IOC與AOP的文章,借此轉發一下,希望能夠幫助到更多的人。 原文地址:https://blog.csdn.net/gloomy_114/article/deta

LINUX系統服務器上搭建DHCP服務,實現基本功能1,自動分配ip;2,手工指定ip

完成 重啟 釋放 p地址 進行 基本功 blog process 自動 在linux系統服務器上搭建DHCP服務,實現兩大基本功能:1,自動分配ip地址;2,手動指定ip地址。首先準備兩臺虛擬機作為實驗對象,一個linux系統作為服務器,一個windows7系統作為客戶機,

Vivado IP的種綜合方式Global Out-Of-Context

在最新的Vivado的版本中,定製IP的時候,會有一個綜合方式的選擇,如下圖所示。可以看到一種叫做”Global”,一種叫”Out-Of-Context (OOC)”。從字面意思上來理解,”Out-Of-Context”是“脫離上下文”的意思。”Global”即全域性。

python網路爬蟲(web spider)系統化整理總結(二)爬蟲python程式碼示例(種響應格式jsonhtml)

        上一篇部落格(入門知識篇),對爬蟲有了一個基本的瞭解,但是具體怎麼實現一個爬蟲程式呢?         一般情況下,我們在瀏覽器獲取資訊,是

Android圖片壓縮的個開源庫LubanCompressor

Luban https://github.com/Curzibn/Luban Luban,也稱魯班。該庫作者一針見血的提出當前圖片壓縮處理的一些問題:單純對圖片進行裁切,壓縮已經有很多文章介紹。但是裁切成多少,壓縮成多少卻很難控制好,裁切過

OrCAD Capture CIS中個重要概念instance occurrences

用OrCAD設計原理圖必須理解兩個概念instance 和 occurrences。對於元件放置、替換、修改屬性等很多操作都和這兩個概念有關。   拋開抽象的說明,我們用例項說明他們的區別。假如你在自己的元件庫中已經建立了一個元件AD8056(AD公司的運放)。

Tensorflow框架種cost函式MSEMulti-class

import tensorflow as tf def MSE_cost(out,Y): cost = tf.reduce_mean(tf.square(out-Y)) return cost def multiclass_cost(out,Y): cost = tf

Http種請求方式Get Post的區別

什麼是HTTP? 超文字傳輸協議(HyperText Transfer Protocol – HTTP)是一個設計來使客戶端和伺服器順利進行通訊的協議。 HTTP在客戶端和伺服器之間以request-response protocol(請求-回覆協議)工作。 get:從指定的伺服器中獲取

pandas的種資料型別SeriesDataFrame

首先要明確pandas是做什麼的,在確定是如何做的,通過哪些方式去做的? pandas是做什麼的?      Python Data Analysis Library 或 pandas 是基於NumPy 的一種工具,該工具是為了解決資料分析任務而建立的。Pandas 納入

推薦款實用工具hcacheSQLPad

hcache Linux使用者可能經常遇到的一個問題是記憶體大部分都被Buff和Cache佔用了,但是有時候我們想知道到底Cache了些什麼內容卻沒有一個直觀好用的工具。今天給你介紹一個可以檢視Linux當前快取了哪些檔案的小工具hcache。 hcache是基於pcstat的,pcstat可以檢視

程式猿的必備神器Git遠端倉庫的使用手法詳解

作為一個程式猿,如果說你對這個GitHub不瞭解,那麼就很尷尬了! 學會使用這個東東是很有必要的! 至於為什麼往下看就是了。 如果看完,你有了想法,就去試著去GitHub註冊個賬號,然後安裝一下,再試著操作一遍! 注:以下命令是在Linux環境下的命令,記得哦,

Java實現記憶體可見性的種方法比較synchronized Volatile以及涉及到的剖析

這篇文中講述了通過synchronized和 volatile 變數實現記憶體可見性的方法,這裡比較下二者的區別。 * volatile 變數是一種稍弱的同步機制在訪問 volatile 變數時不會執行加鎖操作,因此也就不會使執行執行緒阻塞,因此 vola

Java記憶體之本地記憶體分析神器 NMT pmap

背景 其他團隊的一些同事經常問我一個問題:你的Java程序怎麼佔了那麼多Virtual Size和RSS? 最近,我基本上可以回答清楚這個問題了。用NMT和pmap基本就就能搞清楚Java程序為什麼佔了那些Virtual Size和RSS。 NMT是Nativ

資料操作刪除去重

一些看似簡單的資料操作,當作用於海量資料集時,就會出現“意料之外,卻在情理之中”的問題,海量資料操作,需要採用特殊方法,才能“曲徑通幽”。在刪除海量資料時,需要注意日誌的增長,索引碎片的增加和資料庫的恢復模式,特別是利用大容量日誌操作,來減少日誌的增長和提高資料插入的速度。對於大資料去重,通過一些小小的改進