??? 鎖機(jī)制是數(shù)據(jù)庫(kù)系統(tǒng)區(qū)別于文件系統(tǒng)的一個(gè)關(guān)鍵特性,他可以確保用戶能以一致的方式讀取和修改數(shù)據(jù)。
??? 為了保證一致性,必須有鎖的介入。MySQL操作緩沖池中的LRU列表,刪除、添加、移動(dòng)LRU列表中的元素等地方也都適用鎖,從而允許對(duì)多種不同資源的并發(fā)訪問(wèn)。
??? 打個(gè)比方,我們到淘寶上買(mǎi)一件商品,商品只有一件庫(kù)存,這個(gè)時(shí)候如果還有另一個(gè)人買(mǎi),那么如何解決是你買(mǎi)到還是另一個(gè)人買(mǎi)到的問(wèn)題?
??? 這里肯定要用到事物,我們先從庫(kù)存表中取出物品數(shù)量,然后插入訂單,付款后插入付款表信息,然后更新商品數(shù)量。在這個(gè)過(guò)程中,使用鎖可以 對(duì)有限的資源進(jìn)行保護(hù) ,解決隔離和并發(fā)的矛盾。???
MySQL的鎖管理機(jī)制:
- Meta-data元數(shù)據(jù)鎖:在table cache緩存里實(shí)現(xiàn)的,為DDL(Data Definition Language)提供隔離操作。一種特別的meta-data元數(shù)據(jù)類(lèi)型,叫 Name Lock 。(SQL層)
- 表級(jí)table-level數(shù)據(jù)鎖(SQL層)
- 存儲(chǔ)引擎特有機(jī)制 — row locks行鎖,page locks頁(yè)鎖,table locks表級(jí) ,版本控制(在引擎中實(shí)現(xiàn))
- 全局讀鎖 — FLUSH TABLES WITH READ LOCK(SQL層)
上張圖:
?
MySQL的鎖執(zhí)行流程:
- 計(jì)算語(yǔ)句使用到的所有表
- 在每個(gè)表:打開(kāi)open表 — 從table cache緩存里得到TABLE對(duì)象,并在此表加上meta-data元數(shù)據(jù)鎖
- 等待全局讀鎖后改變數(shù)據(jù)
- 在每個(gè)表:鎖lock表 — 在表加上table-level數(shù)據(jù)鎖
- 執(zhí)行語(yǔ)句:調(diào)用:handler::write_row()/read_rnd()/read_index(),等;隱式地調(diào)用引擎級(jí)engine-level鎖機(jī)制
- 在每個(gè)表:釋放表的數(shù)據(jù)鎖
- 在每個(gè)表:釋放表的DDL鎖并把表放回table cache緩存里
- DDL語(yǔ)句也是一樣,沒(méi)有典型的執(zhí)行計(jì)劃。
?
MySQL三種鎖地級(jí)別:頁(yè)級(jí)、表級(jí)、行級(jí)。
三種鎖地特性:
??? 表級(jí)鎖:開(kāi)銷(xiāo)小,加鎖快;不會(huì)出現(xiàn)死鎖;鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)度最低。
??? 行級(jí)鎖:開(kāi)銷(xiāo)稍大,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。
??? 頁(yè)面鎖:開(kāi)銷(xiāo)和加鎖時(shí)間界于表鎖和行鎖之間;會(huì)出現(xiàn)死鎖;鎖定粒度界于表鎖和行鎖之間,并發(fā)度一般。
???
??? 在執(zhí)行SQL語(yǔ)句時(shí),會(huì)實(shí)現(xiàn)存儲(chǔ)引擎內(nèi)部鎖,比如InnoDB存儲(chǔ)引擎的“行鎖”(MyISAM存儲(chǔ)引擎只支持表鎖,而InnoDB存儲(chǔ)引擎支持行鎖。實(shí)際上, 行鎖并不總是會(huì)增加開(kāi)銷(xiāo) ,只有當(dāng)實(shí)現(xiàn)本身增加開(kāi)銷(xiāo)時(shí),行鎖才會(huì)增加開(kāi)銷(xiāo))。
?
表鎖:
手動(dòng)增加表鎖:
lock table XXX read(write);
釋放表鎖:
unlock tables;
?
表級(jí)鎖性能監(jiān)控:
show status like ‘table%’;
如果Table_locks_waited的值比較高,則說(shuō)明存在著比較嚴(yán)重的表鎖爭(zhēng)用情況。
?
表級(jí)鎖的鎖模式:表共享讀鎖(Table Read Lock)和 表獨(dú)占寫(xiě)鎖(Table Write Lock)
??? MyISAM在執(zhí)行查詢(xún)語(yǔ)句(SELECT)前,會(huì)自動(dòng)給涉及的所有表加讀鎖,在執(zhí)行更新操作(UPDATE、DELETE、INSERT等)前,會(huì)自動(dòng)給涉及的表加寫(xiě)鎖。
??? 所以對(duì)MyISAM表進(jìn)行操作,會(huì)有以下情況:
???????? a、對(duì)MyISAM表的讀操作(加讀鎖),不會(huì)阻塞其他進(jìn)程對(duì)同一表的讀請(qǐng)求,但會(huì)阻塞對(duì)同一表的寫(xiě)請(qǐng)求。只有當(dāng)讀鎖釋放后,才會(huì)執(zhí)行其它進(jìn)程的寫(xiě)操作。
??????? b、對(duì)MyISAM表的寫(xiě)操作(加寫(xiě)鎖),會(huì)阻塞其他進(jìn)程對(duì)同一表的讀和寫(xiě)操作,只有當(dāng)寫(xiě)鎖釋放后,才會(huì)執(zhí)行其它進(jìn)程的讀寫(xiě)操作。
??? 簡(jiǎn)而言之,就是讀鎖會(huì)阻塞寫(xiě),但是不會(huì)堵塞讀。而寫(xiě)鎖則會(huì)把讀和寫(xiě)都堵塞。
?
關(guān)于表鎖并發(fā)插入
?
??? 原則上數(shù)據(jù)表有一個(gè)讀鎖時(shí),其它進(jìn)程無(wú)法對(duì)此表進(jìn)行更新操作,但在一定條件下,MyISAM表也支持查詢(xún)和插入操作的并發(fā)進(jìn)行。
??? MyISAM存儲(chǔ)引擎有一個(gè)系統(tǒng)變量
concurrent_insert
,專(zhuān)門(mén)用以控制其并發(fā)插入的行為,其值分別可以為0、1或2。
??????? a、當(dāng)concurrent_insert設(shè)置為0時(shí),不允許并發(fā)插入。
??????? b、
當(dāng)concurrent_insert設(shè)置為1時(shí),如果MyISAM表中沒(méi)有空洞(即表的中間沒(méi)有被刪除的行),MyISAM允許在一個(gè)進(jìn)程讀表的同時(shí),另一個(gè)進(jìn)程從表尾插入記錄。這也是MySQL的默認(rèn)設(shè)置。
??????? c、當(dāng)concurrent_insert設(shè)置為2時(shí),無(wú)論MyISAM表中有沒(méi)有空洞,都允許在表尾并發(fā)插入記錄。
?
表鎖地優(yōu)化:
??? 使用表級(jí)鎖定在鎖定實(shí)現(xiàn)的過(guò)程中比實(shí)現(xiàn)行級(jí)鎖定或頁(yè)級(jí)鎖定所帶來(lái)的附加成本要小,鎖定本身所消耗的資源也是最少的。但是由于鎖定的顆粒度比較大,所以造成鎖定資源的爭(zhēng)用情況也會(huì)比其他的鎖定級(jí)別都要多,從而在較大程度上會(huì)降低并發(fā)處理能力。所以表鎖優(yōu)化, 最關(guān)鍵的是如何讓其提高并發(fā)度 。由于鎖定級(jí)別是不可能改變的了,所以首先需要盡可能地鎖定的時(shí)間變短,然后就是讓可能并發(fā)進(jìn)行的操作盡可能地并發(fā)。
1.縮短鎖定時(shí)間:
??? 1)盡量減少大的復(fù)雜的Query,將復(fù)雜的Query分拆成幾個(gè)小的Query分步進(jìn)行;
??? 2)盡可能地建立足夠高效的索引,讓數(shù)據(jù)檢索更迅速;
??? 3)盡量讓MyISAM存儲(chǔ)引擎的表至存放必要的信息,控制字段類(lèi)型;
??? 4)利用合理的機(jī)會(huì)優(yōu)化MyISAM表數(shù)據(jù)文件。
??? 2、分離能并行的操作
2.合理利用上面提到的concurrent_insert
3.合理利用讀寫(xiě)優(yōu)先級(jí):
??? MyISAM的表級(jí)鎖定對(duì)于讀和寫(xiě)是有不同優(yōu)先級(jí)設(shè)定的, 默認(rèn) 情況下是寫(xiě)優(yōu)先級(jí)要大于讀 。所以,可以根據(jù)系統(tǒng)環(huán)境的差異決定讀與寫(xiě)的優(yōu)先級(jí)。如果系統(tǒng)是一個(gè)以讀為主,而且要優(yōu)先保證查詢(xún)性能的話,可以通過(guò)設(shè)置系統(tǒng)參數(shù)選項(xiàng)low_priority_updates=1,將寫(xiě)的優(yōu)先級(jí)設(shè)置為比讀低,即告訴MyISAM盡量?jī)?yōu)先處理讀請(qǐng)求。當(dāng)然,如果系統(tǒng)需要優(yōu)先保證數(shù)據(jù)寫(xiě)入的性能的話,則不用設(shè)置low_priority_updates參數(shù)了。
?
??? 以上筆記參考網(wǎng)絡(luò)資料以及《MySQL技術(shù)內(nèi)幕:InnoDB存儲(chǔ)引擎》,如有謬誤請(qǐng) 指正 。
??? 下一次整理一下行鎖的筆記~
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
