標籤:
1、鎖機制
1)在處理並發讀寫時,通常使用一套鎖系統來解決問題。鎖系統由讀鎖(又稱共用鎖定)和寫鎖(又稱獨佔鎖定)組成。
2)每一種鎖操作(如獲得鎖、檢查鎖是否已解除、釋放鎖),都會增加系統開銷。鎖策略就是在鎖開銷和資料安全之間尋求一種平衡。MySQL的每種儲存引擎都可以實現專屬的鎖策略或鎖粒度。在儲存引擎設計中,鎖管理是個非常重要的議題。兩種最重要的鎖策略:
(1)行級鎖:可以支援最大的並發處理能力,但也帶來最大的鎖開銷。行級鎖由儲存引擎(如InnoDB)實現,伺服器完全不瞭解儲存引擎裡的鎖實現方式。
(2)表級鎖:開銷最小。
由於通常認為表更新比表檢索更重要,因此寫鎖比讀鎖有更高的優先順序。
雖然儲存引擎管理自己的鎖,但MySQL本身也能使用各種有效表級鎖,如MySQL伺服器在ALTER TABLE語句中使用表級鎖,而不用考慮儲存引擎。
以下的內容僅用於討論MyISAM(如)。對於使用InnoDB儲存引擎的表,讀者可以自行測試。
使用表級鎖的時候,讀寫一般是串列的。但使用READ LOCAL表級鎖可以支援某種類型的並發寫操作,如下面的圖文說明:
I、此時concurrent_insert變數為1,且表沒有出現空洞(自表建立以來,還沒有刪除操作)。,在session 1中對錶使用read local表級鎖,在session 2中可以執行插入操作,但session 1要unlock tables之後才能看到session 2剛剛插入的資料。圖中序號標識操作的順序。
以下三種情況可以用來作為對比,圖略:
若session 1使用read local表級鎖,session 2執行update操作,則會被阻塞。
若session 1隻使用read表級鎖,自然地,session 2插入資料時會阻塞,直到讀鎖釋放。
若session 1獲得讀鎖(read和read local),則它再進行插入或更新操作時都會報錯。
II、此時concurrent_insert變數為1。刪除id=4的記錄,表出現了空洞。,在session 1中對錶使用read local表級鎖,則session 2的插入操作會阻塞。
此時可以使用optimize table來進行磁碟重組。,使用該命令之後,上述的並發插入操作不再阻塞。
III、還是上面的表(使用optimize table之前的有空洞的表),但設定concurrent_insert為2。,session 1對錶使用了read local表級鎖,session 2可以執行插入操作。
總結:
read local和read都是表級讀鎖,但前者允許在一定條件下,對讀鎖定的表執行並發插入操作。
concurrent_insert全域變數可以通過兩種方式取得:在mysql命令列中執行show global variables like ‘%concurrent_insert%‘;,或者在shell命令列中執行mysqladmin -u username -p passwd variables |grep concurrent_insert;另外,可以通過set global concurrent_insert = 0/1/2設定該變數。它主要用於控制並發插入行為:
當它為0時,不允許並發插入(與實際測試不符?);
當它為1(預設值)時,若表不存在空洞,則允許並發插入;否則,不允許並發插入;
當它為2時,即使表存在空洞,也允許並發插入。
為什麼表存在空洞與否對並發插入有影響呢?參考mysql命令列的help optimize table命令(“刪除的行會在一個鏈表中維護,並且後續的插入操作會重用這些舊有的行的位置”),再結合上面的討論,可知大概的組織圖如下。
表中不存在空洞時,插入資料會在圖中最下方的地區,此時無論concurrent_insert為1還是2,插入操作都不會和鎖構成“競爭”關係,因此不會阻塞;表存在空洞時,由於系統要重用空洞地區,所以區分了以下情形:concurrent_insert為1時,認為是要重用空洞地區,但由於被鎖定,所以插入操作阻塞;concurrent_insert為2時,認為先暫時不用空洞地區,而是插入到圖中最下方的地區,和鎖構不成“競爭”關係,因而插入操作不會阻塞。
optimize table磁碟重組之後,圖中空洞地區被重用,即不再存在空洞,因此concurrent_insert為1時,也可以執行並發插入操作了。
另外,update操作由於是更新read local鎖定的地區內的記錄,和鎖構成“競爭”關係,所以會阻塞。
參考資料:
《高效能MySQL》
不斷學習中。。。
MySQL架構基本知識