本篇文章為大家展示了如何理解MySQL的鎖機(jī)制,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。
創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括博興網(wǎng)站建設(shè)、博興網(wǎng)站制作、博興網(wǎng)頁(yè)制作以及博興網(wǎng)絡(luò)營(yíng)銷策劃等。多年來(lái),我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,博興網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到博興省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
當(dāng)前MySQL已經(jīng)支持 ISAM
, MyISAM
, MEMORY
(HEAP
) 類型表的表級(jí)鎖了,BDB
表支持頁(yè)級(jí)鎖,InnoDB
表支持行級(jí)鎖。
很多時(shí)候,可以通過(guò)經(jīng)驗(yàn)來(lái)猜測(cè)什么樣的鎖對(duì)應(yīng)用程序更合適,不過(guò)通常很難說(shuō)一個(gè)鎖比別的更好,這全都要依據(jù)應(yīng)用程序來(lái)決定,不同的地方可能需要不同的鎖。
想要決定是否需要采用一個(gè)支持行級(jí)鎖的存儲(chǔ)引擎,就要看看應(yīng)用程序都要做什么,其中的查詢、更新語(yǔ)句是怎么用的。例如,很多的web應(yīng)用程序大量的做查詢,很少刪除,主要是基于索引的更新,只往特定的表中插入記錄。采用基本的MySQL MyISAM
表就很合適了。
MySQL中對(duì)表級(jí)鎖的存儲(chǔ)引擎來(lái)說(shuō)是釋放死鎖的。避免死鎖可以這樣做到:在任何查詢之前先請(qǐng)求鎖,并且按照請(qǐng)求的順序鎖表。
MySQL中用于 WRITE(寫(xiě))
的表鎖的實(shí)現(xiàn)機(jī)制如下:
如果表沒(méi)有加鎖,那么就加一個(gè)寫(xiě)鎖。
否則的話,將請(qǐng)求放到寫(xiě)鎖隊(duì)列中。
MySQL中用于 READ(讀)
的表鎖的實(shí)現(xiàn)機(jī)制如下:
如果表沒(méi)有加寫(xiě)鎖,那么就加一個(gè)讀鎖。
否則的話,將請(qǐng)求放到讀鎖隊(duì)列中。
當(dāng)鎖釋放后,寫(xiě)鎖隊(duì)列中的線程可以用這個(gè)鎖資源,然后才輪到讀鎖隊(duì)列中的線程。
這就是說(shuō),如果表里有很多更新操作的話,那么 Select
必須等到所有的更新都完成了之后才能開(kāi)始。
從 MySQL 3.23.33 開(kāi)始,可以通過(guò)狀態(tài)變量 Table_locks_waited
和 Table_locks_immediate
來(lái)分析系統(tǒng)中的鎖表爭(zhēng)奪情況:
mysql> SHOW STATUS LIKE 'Table%';+-----------------------+---------+| Variable_name | Value |+-----------------------+---------+| Table_locks_immediate | 1151552 || Table_locks_waited | 15324 |+-----------------------+---------+
在 MySQL 3.23.7(在Windows上是3.23.25)以后,在 MyISAM
表中只要沒(méi)有沖突的 Insert
操作,就可以無(wú)需使用鎖表自由地并行執(zhí)行 Insert
和 Select
語(yǔ)句。也就是說(shuō),可以在其它客戶端正在讀取 MyISAM
表記錄的同時(shí)時(shí)插入新記錄。如果數(shù)據(jù)文件的中間沒(méi)有空余的磁盤塊的話,就不會(huì)發(fā)生沖突了,因?yàn)檫@種情況下所有的新記錄都會(huì)寫(xiě)在數(shù)據(jù)文件的末尾(當(dāng)在表的中間做刪除或者更新操作時(shí),就可能導(dǎo)致空洞)。當(dāng)空洞被新數(shù)據(jù)填充后,并行插入特性就會(huì)自動(dòng)重新被啟用了。
如果想要在一個(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;
InnoDB
使用行級(jí)鎖,BDB
使用頁(yè)級(jí)鎖。對(duì)于 InnoDB
和 BDB
存儲(chǔ)引擎來(lái)說(shuō),是可能產(chǎn)生死鎖的。這是因?yàn)?InnoDB
會(huì)自動(dòng)捕獲行鎖,BDB
會(huì)在執(zhí)行 SQL 語(yǔ)句時(shí)捕獲頁(yè)鎖的,而不是在事務(wù)的開(kāi)始就這么做。
行級(jí)鎖的優(yōu)點(diǎn)有:
在很多線程請(qǐng)求不同記錄時(shí)減少?zèng)_突鎖。
事務(wù)回滾時(shí)減少改變數(shù)據(jù)。
使長(zhǎng)時(shí)間對(duì)單獨(dú)的一行記錄加鎖成為可能。
行級(jí)鎖的缺點(diǎn)有:
比頁(yè)級(jí)鎖和表級(jí)鎖消耗更多的內(nèi)存。
當(dāng)在大量表中使用時(shí),比頁(yè)級(jí)鎖和表級(jí)鎖更慢,因?yàn)樗枰?qǐng)求更多的所資源。
當(dāng)需要頻繁對(duì)大部分?jǐn)?shù)據(jù)做 GROUP BY
操作或者需要頻繁掃描整個(gè)表時(shí),就明顯的比其它鎖更糟糕。
使用更高層的鎖的話,就能更方便的支持各種不同的類型應(yīng)用程序,因?yàn)檫@種鎖的開(kāi)銷比行級(jí)鎖小多了。
表級(jí)鎖在下列幾種情況下比頁(yè)級(jí)鎖和行級(jí)鎖更優(yōu)越:
很多操作都是讀表。
在嚴(yán)格條件的索引上讀取和更新,當(dāng)更新或者刪除可以用單獨(dú)的索引來(lái)讀取得到時(shí):
Updatetbl_nameSETcolumn=valueWhereunique_key_col=key_value; Delete FROMtbl_nameWhereunique_key_col=key_value;
Select
和 Insert
語(yǔ)句并發(fā)的執(zhí)行,但是只有很少的 Update
和 Delete
語(yǔ)句。
很多的掃描表和對(duì)全表的 GROUP BY
操作,但是沒(méi)有任何寫(xiě)表。
表級(jí)鎖和行級(jí)鎖或頁(yè)級(jí)鎖之間的不同之處還在于:
將同時(shí)有一個(gè)寫(xiě)和多個(gè)讀的地方做版本(例如在MySQL中的并發(fā)插入)。也就是說(shuō),數(shù)據(jù)庫(kù)/表支持根據(jù)開(kāi)始訪問(wèn)數(shù)據(jù)時(shí)間點(diǎn)的不同支持各種不同的試圖。其它名有:時(shí)間行程,寫(xiě)復(fù)制,或者是按需復(fù)制。
原文: Versioning (such as we use in MySQL for concurrent inserts) where you can have one writer at the same time as many readers. This means that the database/table supports different views for the data depending on when you started to access it. Other names for this are time travel, copy on write, or copy on demand.
按需復(fù)制在很多情況下比頁(yè)級(jí)鎖或行級(jí)鎖好多了。盡管如此,最壞情況時(shí)還是比其它正常鎖使用了更多的內(nèi)存。
可以用應(yīng)用程序級(jí)鎖來(lái)代替行級(jí)鎖,例如MySQL中的 GET_LOCK()
和 RELEASE_LOCK()
。但它們是勸告鎖(原文:These are advisory locks),因此只能用于安全可信的應(yīng)用程序中。
為了能有快速的鎖,MySQL除了 InnoDB
和 BDB
這兩種存儲(chǔ)引擎外,所有的都是用表級(jí)鎖(而非頁(yè)、行、列級(jí)鎖)。
對(duì)于 InnoDB
和 BDB
表,MySQL只有在指定用 LOCK TABLES
鎖表時(shí)才使用表級(jí)鎖。在這兩種表中,建議最好不要使用 LOCK TABLES
,因?yàn)?InnoDB
自動(dòng)采用行級(jí)鎖,BDB
用頁(yè)級(jí)鎖來(lái)保證事務(wù)的隔離。
如果數(shù)據(jù)表很大,那么在大多數(shù)應(yīng)用中表級(jí)鎖會(huì)比行級(jí)鎖好多了,不過(guò)這有一些陷阱。
表級(jí)鎖讓很多線程可以同時(shí)從數(shù)據(jù)表中讀取數(shù)據(jù),但是如果另一個(gè)線程想要寫(xiě)數(shù)據(jù)的話,就必須要先取得排他訪問(wèn)。正在更新數(shù)據(jù)時(shí),必須要等到更新完成了,其他線程才能訪問(wèn)這個(gè)表。
更新操作通常認(rèn)為比讀取更重要,因此它的優(yōu)先級(jí)更高。不過(guò)最好要先確認(rèn),數(shù)據(jù)表是否有很高的 Select
操作,而更新操作并非很‘急需’。
表鎖鎖在一個(gè)線程在等待,因?yàn)榇疟P空間滿了,但是卻需要有空余的磁盤空間,這個(gè)線程才能繼續(xù)處理時(shí)就有問(wèn)題了。這種情況下,所有要訪問(wèn)這個(gè)出問(wèn)題的表的線程都會(huì)被置為等待狀態(tài),直到有剩余磁盤空間了。
表鎖在以下設(shè)想情況中就不利了:
一個(gè)客戶端提交了一個(gè)需要長(zhǎng)時(shí)間運(yùn)行的 Select
操作。
其他客戶端對(duì)同一個(gè)表提交了 Update
操作,這個(gè)客戶端就要等到 Select
完成了才能開(kāi)始執(zhí)行。
其他客戶端也對(duì)同一個(gè)表提交了 Select
請(qǐng)求。由于 Update
的優(yōu)先級(jí)高于 Select
,所以 Select
就會(huì)先等到 Update
完成了之后才開(kāi)始執(zhí)行,它也在等待第一個(gè) Select
操作。
下列所述可以減少表鎖帶來(lái)的資源爭(zhēng)奪:
讓 Select
速度盡量快,這可能需要?jiǎng)?chuàng)建一些摘要表。
啟動(dòng) mysqld
時(shí)使用參數(shù) --low-priority-updates
。這就會(huì)讓更新操作的優(yōu)先級(jí)低于 Select
。這種情況下,在上面的假設(shè)中,第二個(gè) Select
就會(huì)在 Insert
之前執(zhí)行了,而且也無(wú)需等待第一個(gè)Select
了。
可以執(zhí)行 SET LOW_PRIORITY_UpdateS=1
命令,指定所有的更新操作都放到一個(gè)指定的鏈接中去完成。詳情請(qǐng)看“14.5.3.1 SET
Syntax”。
用 LOW_PRIORITY
屬性來(lái)降低 Insert
,Update
,Delete
的優(yōu)先級(jí)。
用 HIGH_PRIORITY
來(lái)提高 Select
語(yǔ)句的優(yōu)先級(jí)。詳情請(qǐng)看“14.1.7 Select
Syntax”。
從MySQL 3.23.7 開(kāi)始,可以在啟動(dòng) mysqld
時(shí)指定系統(tǒng)變量 max_write_lock_count
為一個(gè)比較低的值,它能強(qiáng)制臨時(shí)地提高表的插入數(shù)達(dá)到一個(gè)特定值后的所有 Select
操作的優(yōu)先級(jí)。它允許在 WRITE
鎖達(dá)到一定數(shù)量后有 READ
鎖。
當(dāng) Insert
和 Select
一起使用出現(xiàn)問(wèn)題時(shí),可以轉(zhuǎn)而采用 MyISAM
表,它支持并發(fā)的Select
和 Insert
操作。
當(dāng)在同一個(gè)表上同時(shí)有插入和刪除操作時(shí),Insert DELAYED
可能會(huì)很有用。詳情請(qǐng)看“14.1.4.2 Insert DELAYED
Syntax”。
當(dāng) Select
和 Delete
一起使用出現(xiàn)問(wèn)題時(shí),Delete
的 LIMIT
參數(shù)可能會(huì)很有用。詳情請(qǐng)看“14.1.1 Delete
Syntax”
執(zhí)行 Select
時(shí)使用 SQL_BUFFER_RESULT
有助于減短鎖表的持續(xù)時(shí)間.詳情請(qǐng)看“14.1.7 Select
Syntax”。
可以修改源代碼 `mysys/thr_lock.c',只用一個(gè)所隊(duì)列。這種情況下,寫(xiě)鎖和讀鎖的優(yōu)先級(jí)就一樣了,這對(duì)一些應(yīng)用可能有幫助。
以下是MySQL鎖的一些建議:
只要對(duì)同一個(gè)表沒(méi)有大量的更新和查詢操作混在一起,目前的用戶并不是問(wèn)題。
執(zhí)行 LOCK TABLES
來(lái)提高速度(很多更新操作放在一個(gè)鎖之中比沒(méi)有鎖的很多更新快多了)。將數(shù)據(jù)拆分開(kāi)到多個(gè)表中可能也有幫助。
當(dāng)MySQL碰到由于鎖表引起的速度問(wèn)題時(shí),將表類型轉(zhuǎn)換成 InnoDB
或 BDB
可能有助于提高性能。詳情請(qǐng)看“16 The InnoDB
Storage Engine”和“15.4 The BDB
(BerkeleyDB
) Storage Engine”。
上述內(nèi)容就是如何理解mysql的鎖機(jī)制,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。