MySQL行級(jí)鎖、表級(jí)鎖、頁級(jí)鎖詳細(xì)介紹
頁級(jí):引擎 BDB。
表級(jí):引擎 MyISAM , 理解為鎖住整個(gè)表,可以同時(shí)讀,寫不行
行級(jí):引擎 INNODB , 單獨(dú)的一行記錄加鎖
表級(jí),直接鎖定整張表,在你鎖定期間,其它進(jìn)程無法對(duì)該表進(jìn)行寫操作。如果你是寫鎖,則其它進(jìn)程則讀也不允許
行級(jí),,僅對(duì)指定的記錄進(jìn)行加鎖,這樣其它進(jìn)程還是可以對(duì)同一個(gè)表中的其它記錄進(jìn)行操作。
頁級(jí),表級(jí)鎖速度快,但沖突多,行級(jí)沖突少,但速度慢。所以取了折衷的頁級(jí),一次鎖定相鄰的一組記錄。
MySQL 5.1支持對(duì)MyISAM和MEMORY表進(jìn)行表級(jí)鎖定,對(duì)BDB表進(jìn)行頁級(jí)鎖定,對(duì)InnoDB表進(jìn)行行級(jí)鎖定。
對(duì)WRITE,MySQL使用的表鎖定方法原理如下:
如果在表上沒有鎖,在它上面放一個(gè)寫鎖。
否則,把鎖定請(qǐng)求放在寫鎖定隊(duì)列中。
對(duì)READ,MySQL使用的鎖定方法原理如下:
如果在表上沒有寫鎖定,把一個(gè)讀鎖定放在它上面
否則,把鎖請(qǐng)求放在讀鎖定隊(duì)列中。
InnoDB使用行鎖定,BDB使用頁鎖定。對(duì)于這兩種存儲(chǔ)引擎,都可能存在死鎖。這是因?yàn)椋赟QL語句處理期間,InnoDB自動(dòng)獲得行鎖定和BDB獲得頁鎖定,而不是在事務(wù)啟動(dòng)時(shí)獲得。
行級(jí)鎖定的優(yōu)點(diǎn):
· 當(dāng)在許多線程中訪問不同的行時(shí)只存在少量鎖定沖突。
· 回滾時(shí)只有少量的更改。
· 可以長(zhǎng)時(shí)間鎖定單一的行。
行級(jí)鎖定的缺點(diǎn):
· 比頁級(jí)或表級(jí)鎖定占用更多的內(nèi)存。
· 當(dāng)在表的大部分中使用時(shí),比頁級(jí)或表級(jí)鎖定速度慢,因?yàn)槟惚仨毇@取更多的鎖。
· 如果你在大部分?jǐn)?shù)據(jù)上經(jīng)常進(jìn)行GROUP BY操作或者必須經(jīng)常掃描整個(gè)表,比其它鎖定明顯慢很多。
· 用高級(jí)別鎖定,通過支持不同的類型鎖定,你也可以很容易地調(diào)節(jié)應(yīng)用程序,因?yàn)槠滏i成本小于行級(jí)鎖定。
在以下情況下,表鎖定優(yōu)先于頁級(jí)或行級(jí)鎖定:
· 表的大部分語句用于讀取。
· 對(duì)嚴(yán)格的關(guān)鍵字進(jìn)行讀取和更新,你可以更新或刪除可以用單一的讀取的關(guān)鍵字來提取的一行:
· UPDATE tbl_name SET column=value WHERE unique_key_col=key_value;
· DELETE FROM tbl_name WHERE unique_key_col=key_value;
· SELECT 結(jié)合并行的INSERT語句,并且只有很少的UPDATE或DELETE語句。
· 在整個(gè)表上有許多掃描或GROUP BY操作,沒有任何寫操作。
/* ========================= mysql 鎖表類型和解鎖語句 ========================= */
如果想要在一個(gè)表上做大量的 INSERT 和 SELECT 操作,但是并行的插入?yún)s不可能時(shí),可以將記錄插入到臨時(shí)表中,然后定期將臨時(shí)表中的數(shù)據(jù)更新到實(shí)際的表里??梢杂靡韵旅顚?shí)現(xiàn):
mysql> LOCK TABLES real_table WRITE, insert_table WRITE;
mysql> INSERT INTO real_table SELECT * FROM insert_table;
mysql> TRUNCATE TABLE insert_table;
mysql> UNLOCK TABLES;
行級(jí)鎖的優(yōu)點(diǎn)有:
在很多線程請(qǐng)求不同記錄時(shí)減少?zèng)_突鎖。
事務(wù)回滾時(shí)減少改變數(shù)據(jù)。
使長(zhǎng)時(shí)間對(duì)單獨(dú)的一行記錄加鎖成為可能。
行級(jí)鎖的缺點(diǎn)有:
比頁級(jí)鎖和表級(jí)鎖消耗更多的內(nèi)存。
鎖是計(jì)算機(jī)協(xié)調(diào)多個(gè)進(jìn)程或線程并發(fā)訪問某一資源的機(jī)制,不同的數(shù)據(jù)庫的鎖機(jī)制大同小異。由于數(shù)據(jù)庫資源是一種供許多用戶共享的資源,所以如何保證數(shù)據(jù)并發(fā)訪問的一致性、有效性是所有數(shù)據(jù)庫必須解決的一個(gè)問題,鎖沖突也是影響數(shù)據(jù)庫并發(fā)訪問性能的一個(gè)重要因素。了解鎖機(jī)制不僅可以使我們更有效的開發(fā)利用數(shù)據(jù)庫資源,也使我們能夠更好地維護(hù)數(shù)據(jù)庫,從而提高數(shù)據(jù)庫的性能。
MySQL的鎖機(jī)制比較簡(jiǎn)單,其最顯著的特點(diǎn)是不同的存儲(chǔ)引擎支持不同的鎖機(jī)制。
例如,MyISAM和MEMORY存儲(chǔ)引擎采用的是表級(jí)鎖(table-level-locking);BDB存儲(chǔ)引擎采用的是頁面鎖(page-level-locking),同時(shí)也支持表級(jí)鎖;InnoDB存儲(chǔ)引擎既支持行級(jí)鎖,也支持表級(jí)鎖,默認(rèn)情況下是采用行級(jí)鎖。
上述三種鎖的特性可大致歸納如下:
1) 表級(jí)鎖:開銷小,加鎖快;不會(huì)出現(xiàn)死鎖;鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)度最低。
2) 行級(jí)鎖:開銷大,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。
3) 頁面鎖:開銷和加鎖時(shí)間界于表鎖和行鎖之間;會(huì)出現(xiàn)死鎖;鎖定粒度界于表鎖和行鎖之間,并發(fā)度一般。
三種鎖各有各的特點(diǎn),若僅從鎖的角度來說,表級(jí)鎖更適合于以查詢?yōu)橹?,只有少量按索引條件更新數(shù)據(jù)的應(yīng)用,如WEB應(yīng)用;行級(jí)鎖更適合于有大量按索引條件并發(fā)更新少量不同數(shù)據(jù),同時(shí)又有并發(fā)查詢的應(yīng)用,如一些在線事務(wù)處理(OLTP)系統(tǒng)。
MySQL表級(jí)鎖有兩種模式:表共享讀鎖(Table Read Lock)和表獨(dú)占寫鎖(Table Write Lock)。什么意思呢,就是說對(duì)MyISAM表進(jìn)行讀操作時(shí),它不會(huì)阻塞其他用戶對(duì)同一表的讀請(qǐng)求,但會(huì)阻塞 對(duì)同一表的寫操作;而對(duì)MyISAM表的寫操作,則會(huì)阻塞其他用戶對(duì)同一表的讀和寫操作。
MyISAM表的讀和寫是串行的,即在進(jìn)行讀操作時(shí)不能進(jìn)行寫操作,反之也是一樣。但在一定條件下MyISAM表也支持查詢和插入的操作的并發(fā)進(jìn)行,其機(jī)制是通過控制一個(gè)系統(tǒng)變量(concurrent_insert)來進(jìn)行的,當(dāng)其值設(shè)置為0時(shí),不允許并發(fā)插入;當(dāng)其值設(shè)置為1 時(shí),如果MyISAM表中沒有空洞(即表中沒有被刪除的行),MyISAM允許在一個(gè)進(jìn)程讀表的同時(shí),另一個(gè)進(jìn)程從表尾插入記錄;當(dāng)其值設(shè)置為2時(shí),無論MyISAM表中有沒有空洞,都允許在表尾并發(fā)插入記錄。
MyISAM鎖調(diào)度是如何實(shí)現(xiàn)的呢,這也是一個(gè)很關(guān)鍵的問題。例如,當(dāng)一個(gè)進(jìn)程請(qǐng)求某個(gè)MyISAM表的讀鎖,同時(shí)另一個(gè)進(jìn)程也請(qǐng)求同一表的寫鎖,此時(shí)MySQL將會(huì)如優(yōu)先處理進(jìn)程呢?通過研究表明,寫進(jìn)程將先獲得鎖(即使讀請(qǐng)求先到鎖等待隊(duì)列)。但這也造成一個(gè)很大的缺陷,即大量的寫操作會(huì)造成查詢操作很難獲得讀鎖,從而可能造成永遠(yuǎn)阻塞。所幸我們可以通過一些設(shè)置來調(diào)節(jié)MyISAM的調(diào)度行為。我們可通過指定參數(shù)low-priority-updates,使MyISAM默認(rèn)引擎給予讀請(qǐng)求以優(yōu)先的權(quán)利,設(shè)置其值為1(set low_priority_updates=1),使優(yōu)先級(jí)降低。
InnoDB鎖與MyISAM鎖的最大不同在于:一是支持事務(wù)(TRANCSACTION),二是采用了行級(jí)鎖。我們知道事務(wù)是由一組SQL語句組成的邏輯處理單元,其有四個(gè)屬性(簡(jiǎn)稱ACID屬性),分別為:
原子性(Atomicity):事務(wù)是一個(gè)原子操作單元,其對(duì)數(shù)據(jù)的修改,要么全部執(zhí)行,要么全都不執(zhí)行;
一致性(Consistent):在事務(wù)開始和完成時(shí),數(shù)據(jù)都必須保持一致狀態(tài);
隔離性(Isolation):數(shù)據(jù)庫系統(tǒng)提供一定的隔離機(jī)制,保證事務(wù)在不受外部并發(fā)操作影響的“獨(dú)立”環(huán)境執(zhí)行;
持久性(Durable):事務(wù)完成之后,它對(duì)于數(shù)據(jù)的修改是永久性的,即使出現(xiàn)系統(tǒng)故障也能夠保持。
InnoDB有兩種模式的行鎖:
1)共享鎖:允許一個(gè)事務(wù)去讀一行,阻止其他事務(wù)獲得相同數(shù)據(jù)集的排他鎖。
( Select * from table_name where ......lock in share mode)
2)排他鎖:允許獲得排他鎖的事務(wù)更新數(shù)據(jù),阻止其他事務(wù)取得相同數(shù)據(jù)集的共享讀鎖和 排他寫鎖。(select * from table_name where.....for update)
為了允許行鎖和表鎖共存,實(shí)現(xiàn)多粒度鎖機(jī)制;同時(shí)還有兩種內(nèi)部使用的意向鎖(都是表鎖),分別為意向共享鎖和意向排他鎖。
InnoDB行鎖是通過給索引項(xiàng)加鎖來實(shí)現(xiàn)的,即只有通過索引條件檢索數(shù)據(jù),InnoDB才使用行級(jí)鎖,否則將使用表鎖!
另外:插入,更新性能優(yōu)化的幾個(gè)重要參數(shù)
bulk_insert_buffer_size
批量插入緩存大小, 這個(gè)參數(shù)是針對(duì)MyISAM存儲(chǔ)引擎來說的.適用于在一次性插入100-1000+條記錄時(shí), 提高效率.默認(rèn)值是8M.可以針對(duì)數(shù)據(jù)量的大小,翻倍增加.
concurrent_insert
并發(fā)插入, 當(dāng)表沒有空洞(刪除過記錄), 在某進(jìn)程獲取讀鎖的情況下,其他進(jìn)程可以在表尾部進(jìn)行插入.
值可以設(shè)0不允許并發(fā)插入, 1當(dāng)表沒有空洞時(shí), 執(zhí)行并發(fā)插入, 2不管是否有空洞都執(zhí)行并發(fā)插入.
默認(rèn)是1 針對(duì)表的刪除頻率來設(shè)置.
delay_key_write
針對(duì)MyISAM存儲(chǔ)引擎,延遲更新索引.意思是說,update記錄時(shí),先將數(shù)據(jù)up到磁盤,但不up索引,將索引存在內(nèi)存里,當(dāng)表關(guān)閉時(shí),將內(nèi)存索引,寫到磁盤. 值為 0不開啟, 1開啟. 默認(rèn)開啟.
delayed_insert_limit, delayed_insert_timeout, delayed_queue_size
延遲插入, 將數(shù)據(jù)先交給內(nèi)存隊(duì)列, 然后慢慢地插入.但是這些配置,不是所有的存儲(chǔ)引擎都支持, 目前來看, 常用的InnoDB不支持, MyISAM支持. 根據(jù)實(shí)際情況調(diào)大, 一般默認(rèn)夠用了
/* ==================== MySQL InnoDB 鎖表與鎖行 ======================== */
由于InnoDB預(yù)設(shè)是Row-Level Lock,所以只有「明確」的指定主鍵,MySQL才會(huì)執(zhí)行Row lock (只鎖住被選取的資料例) ,否則MySQL將會(huì)執(zhí)行Table Lock (將整個(gè)資料表單給鎖住)。
舉個(gè)例子: 假設(shè)有個(gè)表單products ,里面有id跟name二個(gè)欄位,id是主鍵。
例1: (明確指定主鍵,并且有此筆資料,row lock)
SELECT * FROM products WHERE id='3' and type=1 FOR UPDATE;
例2: (明確指定主鍵,若查無此筆資料,無lock)
例3: (無主鍵,table lock)
例4: (主鍵不明確,table lock)
例5: (主鍵不明確,table lock)
注1: FOR UPDATE僅適用于InnoDB,且必須在交易區(qū)塊(BEGIN/COMMIT)中才能生效。
注2: 要測(cè)試鎖定的狀況,可以利用MySQL的Command Mode ,開二個(gè)視窗來做測(cè)試。
在MySql 5.0中測(cè)試確實(shí)是這樣的
另外:MyAsim 只支持表級(jí)鎖,InnerDB支持行級(jí)鎖
添加了(行級(jí)鎖/表級(jí)鎖)鎖的數(shù)據(jù)不能被其它事務(wù)再鎖定,也不被其它事務(wù)修改(修改、刪除)
是表級(jí)鎖時(shí),不管是否查詢到記錄,都會(huì)鎖定表
此外,如果A與B都對(duì)表id進(jìn)行查詢但查詢不到記錄,則A與B在查詢上不會(huì)進(jìn)行row鎖,但A與B都會(huì)獲取排它鎖,此時(shí)A再插入一條記錄的話則會(huì)因?yàn)锽已經(jīng)有鎖而處于等待中,此時(shí)B再插入一條同樣的數(shù)據(jù)則會(huì)拋出Deadlock found when trying to get lock; try restarting transaction然后釋放鎖,此時(shí)A就獲得了鎖而插入成功
相關(guān)文章
MYSQL突破secure_file_priv寫shell問題
這篇文章主要介紹了MYSQL突破secure_file_priv寫shell問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01實(shí)現(xiàn)MySQL與elasticsearch的數(shù)據(jù)同步的代碼示例
MySQL 自身簡(jiǎn)單、高效、可靠,是又拍云內(nèi)部使用最廣泛的數(shù)據(jù)庫,但是當(dāng)數(shù)據(jù)量達(dá)到一定程度的時(shí)候,對(duì)整個(gè) MySQL 的操作會(huì)變得非常遲緩,這個(gè)時(shí)候我們就需要MySQL與elasticsearch數(shù)據(jù)同步,接下來就給大家介紹如何實(shí)現(xiàn)數(shù)據(jù)同步2023-07-07將舊版MySQL替換為8.0及以上版本保姆級(jí)教學(xué)
在部署項(xiàng)目的時(shí)候MySQL就會(huì)報(bào)錯(cuò),這個(gè)時(shí)候就要換MySQL的版本了,這篇文章主要給大家介紹了關(guān)于將舊版MySQL替換為8.0及以上版本的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2024-05-05MySQL 原理與優(yōu)化之Update 優(yōu)化
這篇文章主要介紹了MySQL 原理與優(yōu)化之Update 優(yōu)化,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下,希望對(duì)你的學(xué)習(xí)有所幫助2022-08-08一個(gè)案例徹底弄懂如何正確使用mysql inndb聯(lián)合索引
今天小編就為大家分享一篇關(guān)于一個(gè)案例徹底弄懂如何正確使用mysql inndb聯(lián)合索引,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-02-02Mysql刪除重復(fù)數(shù)據(jù)并且只保留一條(附實(shí)例!)
最近有朋友打電話尋求一個(gè)SQL相關(guān)的問題,大致是表中存在重復(fù)數(shù)據(jù),需要?jiǎng)h除掉重復(fù)數(shù)據(jù)保留一條的場(chǎng)景,下面這篇文章主要給大家介紹了關(guān)于Mysql刪除重復(fù)數(shù)據(jù)并且只保留一條的相關(guān)資料,需要的朋友可以參考下2023-02-02mysql的基礎(chǔ)語句和外鍵查詢及其語句詳解(推薦)
這篇文章主要介紹了mysql的基礎(chǔ)語句和外鍵查詢及其語句詳解(推薦),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2025-04-04淺談MySQL存儲(chǔ)引擎選擇 InnoDB與MyISAM的優(yōu)缺點(diǎn)分析
MyISAM 是MySQL中默認(rèn)的存儲(chǔ)引擎,一般來說不是有太多人關(guān)心這個(gè)東西。決定使用什么樣的存儲(chǔ)引擎是一個(gè)很tricky的事情,但是還是值我們?nèi)パ芯恳幌拢@里的文章只考慮 MyISAM 和InnoDB這兩個(gè),因?yàn)檫@兩個(gè)是最常見的2013-06-06