主頁 > 資料庫 > 一條簡單的更新陳述句,MySQL是如何加鎖的?

一條簡單的更新陳述句,MySQL是如何加鎖的?

2020-09-22 08:03:39 資料庫

看如下一條sql陳述句:

# table T (id int, name varchar(20))
delete from T where id = 10

MySQL在執行的程序中,是如何加鎖呢?

在看下面這條陳述句:

select * from T where id = 10

那這條陳述句呢?其實這其中包含太多知識點了,要回答這兩個問題,首先需要了解一些知識,

相關知識介紹

多版本并發控制

在MySQL默認存盤引擎InnoDB中,實作的是基于多版本的并發控制協議——MVCC(Multi-Version Concurrency Control)(注:與MVVC相對的,是基于鎖的并發控制,Lock-Based Concurrency Control),其中MVCC最大的好處是:讀不加鎖,讀寫不沖突,在讀多寫少的OLTP應用中,讀寫不沖突是非常重要的,極大的提高了系統的并發性能,在現階段,幾乎所有的RDBMS,都支持MVCC,其實,MVCC就一句話總結:同一份資料臨時保存多個版本的一種方式,進而實作并發控制,

當前讀和快照讀

在MVCC并發控制中,讀操作可以分為兩類:快照讀與當前讀,

快照讀(簡單的select操作):讀取的是記錄中的可見版本(可能是歷史版本),不用加鎖,這你就知道第二個問題的答案了吧,

當前讀(特殊的select操作、insert、delete和update):讀取的是記錄中最新版本,并且當前讀回傳的記錄都會加上鎖,這樣保證了了其他事務不會再并發修改這條記錄,

聚集索引

也叫做聚簇索引,在InnoDB中,資料的組織方式就是聚簇索引:完整的記錄,儲存在主鍵索引中,通過主鍵索引,就可以獲取記錄中所有的列,

最左前綴原則

也就是最左優先,這條原則針對的是組合索引和前綴索引,理解:

1、在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的順序可以任意調整,

2、= 和 in 可以亂序,比如 a = 1 and b = 2 and c = 3 建立(a, b, c)索引可以任意順序,MySQL的查詢優化器會優化索引可以識別的形式,

兩階段鎖

傳統的RDMS加鎖的一個原則,就是2PL(Two-Phase Locking,二階段鎖),也就是說鎖操作分為兩個階段:加鎖階段和解鎖階段,并且保證加鎖階段和解鎖階段不想交,也就是說在一個事務中,不管有多少條增刪改,都是在加鎖階段加鎖,在 commit 后,進入解鎖階段,才會全部解鎖,

隔離級別

MySQL/InnoDB中,定義了四種隔離級別:

Read Uncommitted:可以讀取未提交記錄,此隔離級別不會使用,

Read Committed(RC):針對當前讀,RC隔離級別保證了對讀取到的記錄加鎖(記錄鎖),存在幻讀現象,

Repeatable Read(RR):針對當前讀,RR隔離級別保證對讀取到的記錄加鎖(記錄鎖),同時保證對讀取的范圍加鎖,新的滿足查詢條件的記錄不能夠插入(間隙鎖),不存在幻讀現象,

Serializable:從MVCC并發控制退化為基于鎖的并發控制,不區別快照讀和當前讀,所有的讀操作都是當前讀,讀加讀鎖(S鎖),寫加寫鎖(X鎖),在該隔離級別下,讀寫沖突,因此并發性能急劇下降,在MySQL/InnoDB中不建議使用,

 Gap鎖和Next-Key鎖

在InnoDB中完整行鎖包含三部分:

記錄鎖(Record Lock):記錄鎖鎖定索引中的一條記錄,

間隙鎖(Gap Lock):間隙鎖要么鎖住索引記錄中間的值,要么鎖住第一個索引記錄前面的值或最后一個索引記錄后面的值,

Next-Key Lock:Next-Key鎖時索引記錄上的記錄鎖和在記錄之前的間隙鎖的組合,

進行分析

了解完以上的小知識點,我們開始分析第一個問題,當看到這個問題的時候,你可能會毫不猶豫的說,加寫鎖啊,這答案也錯也對,因為已知條件太少,那么有那些需要已知的前提條件呢?

  • 前提一:id列是不是主鍵?
  • 前提二:當前系統的隔離級別是什么?
  • 前提三:id列如果不是主鍵,那么id列上有沒有索引呢?
  • 前提四:id列上如果有二級索引,那么是唯一索引嗎?
  • 前提五:SQL執行計劃是什么?索引掃描?還是全表掃描

根據上面的前提條件,可以有九種組合,當然還沒有列舉完全,

  1. id列是主鍵,RC隔離級別
  2. id列是二級唯一索引,RC隔離級別
  3. id列是二級不唯一索引,RC隔離級別
  4. id列上沒有索引,RC隔離級別
  5. d列是主鍵,RR隔離級別
  6. id列是二級唯一索引,RR隔離級別
  7. id列是二級不唯一索引,RR隔離級別
  8. id列上沒有索引,RR隔離級別

 組合一:id主鍵 + RC

這個組合是分析最簡單的,到執行該陳述句時,只需要將主鍵id = 10的記錄加上X鎖,如下圖所示:

 

 

結論:id是主鍵是,此SQL陳述句只需要在id = 10這條記錄上加上X鎖即可,

組合二:id唯一索引 + RC

這個組合,id不是主鍵,而是一個Unique的二級索引鍵值,在RC隔離級別下,是怎么加鎖的呢?看下圖:

 

由于id是Unique索引,因此delete陳述句會選擇走id列的索引進行where條件過濾,在找到id = 10的記錄后,首先會將Unique索引上的id = 10的記錄加上X鎖,同時,會根據讀取到的name列,回到主鍵索引(聚簇索引),然后將聚簇索引上的name = 'e' 對應的主鍵索引項加X鎖,

結論:若id列是Unique列,其上有Unique索引,那么SQL需要加兩個X鎖,一個對應于id Unique索引上的id = 10的記錄,另一把鎖對應于聚簇索引上的(name = 'e', id = 10)的記錄,

 組合三:id不唯一索引+RC

該組合中,id列不在唯一,而是個普通索引,那么當執行sql陳述句時,MySQL又是如何加鎖呢?看下圖:

 

由上圖可以看出,首先,id列索引上,滿足id = 10查詢的記錄,均加上X鎖,同時,這些記錄對應的主鍵索引上的記錄也加上X鎖,與組合er的唯一區別,組合二最多只有一個滿足條件的記錄,而在組合三中會將所有滿足條件的記錄全部加上鎖,

結論:若id列上有非唯一索引,那么對應的所有滿足SQL查詢條件的記錄,都會加上鎖,同時,這些記錄在主鍵索引上也會加上鎖,

組合四:id無索引+RC

相對于前面的組合,該組合相對特殊,因為id列上無索引,所以在 where id = 10 這個查詢條件下,沒法通過索引來過濾,因此只能全表掃描做過濾,對于該組合,MySQL又會進行怎樣的加鎖呢?看下圖:

 

由于id列上無索引,因此只能走聚簇索引,進行全表掃描,由圖可以看出滿足條件的記錄只有兩條,但是,聚簇索引上的記錄都會加上X鎖,但在實際操作中,MySQL進行了改進,在進行過濾條件時,發現不滿足條件后,會呼叫 unlock_row 方法,把不滿足條件的記錄放鎖(違背了2PL原則),這樣做,保證了最后滿足條件的記錄加上鎖,但是每條記錄的加鎖操作是不能省略的,

結論:若id列上沒有索引,MySQL會走聚簇索引進行全表掃描過濾,由于是在MySQl Server層面進行的,因此每條記錄無論是否滿足條件,都會加上X鎖,但是,為了效率考慮,MySQL在這方面進行了改進,在掃描程序中,若記錄不滿足過濾條件,會進行解鎖操作,同時優化違背了2PL原則,

組合五:id主鍵+RR

該組合為id是主鍵,Repeatable Read隔離級別,針對于上述的SQL陳述句,加鎖程序和組合一(id主鍵+RC)一致,

組合六:id唯一索引+RR

該組合與組合二的加鎖程序一致,

組合七:id不唯一索引+RR

在組合一到組合四中,隔離級別是Read Committed下,會出現幻讀情況,但是在該組合Repeatable Read級別下,不會出現幻讀情況,這是怎么回事呢?而MySQL又是如何給上述陳述句加鎖呢?看下圖:

 

該組合和組合三看起來很相似,但差別很大,在改組合中加入了一個間隙鎖(Gap鎖),這個Gap鎖就是相對于RC級別下,RR級別下不會出現幻讀情況的關鍵,實質上,Gap鎖不是針對于記錄本身的,而是記錄之間的Gap,所謂幻讀,就是同一事務下,連續進行多次當前讀,且讀取一個范圍內的記錄(包括直接查詢所有記錄結果或者做聚合統計), 發現結果不一致(標準檔案一般指記錄增多, 記錄的減少應該也算是幻讀),

那么該如何解決這個問題呢?如何保證多次當前讀回傳一致的記錄,那么就需要在多個當前讀之間,其他事務不會插入新的滿足條件的記錄并提交,為了實作該結果,Gap鎖就應運而生,

如圖所示,有些位置可以插入新的滿足條件的記錄,考慮到B+樹的有序性,滿足條件的記錄一定是具有連續性的,因此會在 [4, b], [10, c], [10, d], [20, e] 之間加上Gap鎖,

Insert操作時,如insert(10, aa),首先定位到 [4, b], [10, c]間,然后插入在插入之前,會檢查該Gap是否加鎖了,如果被鎖上了,則Insert不能加入記錄,因此通過第一次當前讀,會把滿足條件的記錄加上X鎖,還會加上三把Gap鎖,將可能插入滿足條件記錄的3個Gap鎖上,保證后續的Insert不能插入新的滿足 id = 10 的記錄,也就解決了幻讀問題,

而在組合五,組合六中,同樣是RR級別,但是不用加上Gap鎖,在組合五中id是主鍵,組合六中id是Unique鍵,都能保證唯一性,一個等值查詢,最多只能回傳一條滿足條件的記錄,而且新的相同取值的記錄是無法插入的,

結論:在RR隔離級別下,id列上有非唯一索引,對于上述的SQL陳述句;首先,通過id索引定位到第一條滿足條件的記錄,給記錄加上X鎖,并且給Gap加上Gap鎖,然后在主鍵聚簇索引上滿足相同條件的記錄加上X鎖,然后回傳;之后讀取下一條記錄重復進行,直至第一條出現不滿足條件的記錄,此時,不需要給記錄加上X鎖,但是需要給Gap加上Gap鎖嗎,最后回傳結果,

組合八:id無索引+RR

該組合中,id列上無索引,只能進行全表掃描,那么該如何加鎖,看下圖:

 

如圖,可以看出這是一個很恐怖的事情,全表每條記錄要加X鎖,每個Gap加上Gap鎖,如果表上存在大量資料時,又是什么情景呢?這種情況下,這個表,除了不加鎖的快照讀,其他任何加鎖的并發SQL,均不能執行,不能更新,洗掉,插入,這樣,全表鎖死,

當然,和組合四一樣,MySQL進行了優化,就是semi-consistent read,semi-consistent read開啟的情況下,對于不滿足條件的記錄,MySQL會提前放鎖,同時Gap鎖也會釋放,而semi-consistent read是如何觸發:要么在Read Committed隔離級別下;要么在Repeatable Read隔離級別下,設定了 innodb_locks_unsafe_for_binlog 引數,

結論:在Repeatable Read隔離級別下,如果進行全表掃描的當前讀,那么會鎖上表上的所有記錄,并且所有的Gap加上Gap鎖,杜絕所有的 delete/update/insert 操作,當然在MySQL中,可以觸發 semi-consistent read來緩解鎖開銷與并發影響,但是semi-consistent read本身也會帶來其他的問題,不建議使用,

組合九:Serializable

在最后組合中,對于上訴的洗掉SQL陳述句,加鎖程序和組合八一致,但是,對于查詢陳述句(比如select * from T1 where id = 10)來說,在RC,RR隔離級別下,都是快照讀,不加鎖,在Serializable隔離級別下,無論是查詢陳述句也會加鎖,也就是說快照讀不存在了,MVCC降級為Lock-Based CC,

結論:在MySQL/InnoDB中,所謂的讀不加鎖,并不適用于所有的情況,而是和隔離級別有關,在Serializable隔離級別下,所有的操作都會加鎖,

一條簡單的洗掉陳述句加鎖情況也就分析完成了,但是學習不止于此,還在繼續,對于復雜SQL陳述句又是如何加鎖的呢?MySQL中的索引的分析又是怎樣的呢?性能分析、性能優化這些又是怎么呢?請看后續,

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/103161.html

標籤:MySQL

上一篇:ORDER BY導致索引使用不理想

下一篇:memcache和redis快取對比及我為什么選擇redis

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more