MySQL鎖機制詳解及死鎖處理方式

爲了給高併發狀況下的MySQL進行更好的優化,有必要了解一下MySQL查詢更新時的鎖表機制。mysql

1、概述 MySQL有三種鎖的級別:頁級、表級、行級。 MyISAM和MEMORY存儲引擎採用的是表級鎖(table-level locking);BDB存儲引擎採用的是頁面鎖(page-level locking),但也支持表級鎖;InnoDB存儲引擎既支持行級鎖(row-level locking),也支持表級鎖,但默認狀況下是採用行級鎖。 MySQL這3種鎖的特性可大體概括以下: 表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的機率最高,併發度最低。 行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高。 頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度通常。sql

2、MyISAM表鎖 MyISAM存儲引擎只支持表鎖,是如今用得最多的存儲引擎。 但表級鎖讓多線程能夠同時從數據表中讀取數據,可是若是另外一個線程想要寫數據的話,就必需要先取得排他訪問。正在更新數據時,必需要等到更新完成了,其餘線程才能訪問這個表。(這種機制形成了併發讀寫容易出現表鎖爭奪而致使阻塞訪問) 一、查詢表級鎖爭用狀況 能夠經過檢查table_locks_waited和table_locks_immediate狀態變量來分析系統上的表鎖定爭奪: mysql> show status like 'table%'; +———————–+———-+ | Variable_name | Value | +———————–+———-+ | Table_locks_immediate | 76939364 | (表示能夠當即獲取鎖的次數) | Table_locks_waited | 305089 | (表示不能當即獲取鎖,須要等待鎖的次數;)
+———————–+———-+ 2 rows in set (0.00 sec) Table_locks_waited/(Table_locks_immediate+Table_locks_waited) 這個比例值越大說明表級鎖爭用的狀況越嚴重。 例:比例值=0.01說明100次進程裏就有一次是須要等待鎖的進程;服務器

二、MySQL表級鎖的鎖模式 MySQL的表級鎖有兩種模式:表共享讀鎖(Table Read Lock)和表獨佔寫鎖(Table Write Lock)。MyISAM在執行查詢語句(SELECT)前,會自動給涉及的全部表加讀鎖,在執行更新操做(UPDATE、DELETE、INSERT等)前,會自動給涉及的表加寫鎖。 因此對MyISAM表進行操做,會有如下狀況: a、對MyISAM表的讀操做(加讀鎖),不會阻塞其餘進程對同一表的讀請求,但會阻塞對同一表的寫請求。只有當讀鎖釋放後,纔會執行其它進程的寫操做。 b、對MyISAM表的寫操做(加寫鎖),會阻塞其餘進程對同一表的讀和寫操做,只有當寫鎖釋放後,纔會執行其它進程的讀寫操做。多線程

三、併發插入 原則上數據表有一個讀鎖時,其它進程沒法對此表進行更新操做,但在必定條件下,MyISAM表也支持查詢和插入操做的併發進行。 MyISAM存儲引擎有一個系統變量concurrent_insert,專門用以控制其併發插入的行爲,其值分別能夠爲0、1或2。 a、當concurrent_insert設置爲0時,不容許併發插入。 b、當concurrent_insert設置爲1時,若是MyISAM表中沒有空洞(即表的中間沒有被刪除的行),MyISAM容許在一個進程讀表的同時,另外一個進程從表尾插入記錄。這也是MySQL的默認設置。 c、當concurrent_insert設置爲2時,不管MyISAM表中有沒有空洞,都容許在表尾併發插入記錄。 四、MyISAM的鎖調度 因爲MySQL認爲寫請求通常比讀請求要重要,因此若是有讀寫請求同時進行的話,MYSQL將會優先執行寫操做。這樣MyISAM表在進行大量的更新操做時(特別是更新的字段中存在索引的狀況下),會形成查詢操做很難得到讀鎖,從而致使查詢阻塞。 咱們能夠經過一些設置來調節MyISAM的調度行爲: a、經過指定啓動參數low-priority-updates,使MyISAM引擎默認給予讀請求以優先的權利。 b、經過執行命令SET LOW_PRIORITY_UPDATES=1,使該鏈接發出的更新請求優先級下降。 c、經過指定INSERT、UPDATE、DELETE語句的LOW_PRIORITY屬性,下降該語句的優先級。 上面3種方法都是要麼更新優先,要麼查詢優先的方法。這裏要說明的就是,不要盲目的給mysql設置爲讀優先,由於一些須要長時間運行的查詢操做,也會使寫進程「餓死」。只有根據你的實際狀況,來決定設置哪一種操做優先。 這些方法仍是沒有從根本上同時解決查詢和更新的問題。在一個有大數據量高並發表的mysql裏,咱們還可採用另外一種策略來進行優化,那就是經過mysql主從(讀寫)分離來實現負載均衡,這樣可避免優先哪種操做從而可能致使另外一種操做的堵塞。下面將用一個篇幅來講明mysql的讀寫分離技術。併發

MyISAM使用的是 flock 類的函數,直接就是對整個文件進行鎖定(叫作文件鎖定),InnoDB使用的是 fcntl 類的函數,能夠對文件中局部數據進行鎖定(叫作行鎖定),因此區別就是在這裏。 另外MyISAM的數據表是按照單個文件存儲的,能夠針對單個表文件進行鎖定,可是InnoDB是一整個文件,把索引、數據、結構所有保存在 ibdata 文件裏,因此必須用行鎖定。 死鎖 所謂死鎖<DeadLock>: 是指兩個或兩個以上的進程在執行過程當中, 因爭奪資源而形成的一種互相等待的現象,若無外力做用,它們都將沒法推動下去. 此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等竺的進程稱爲死鎖進程. 表級鎖不會產生死鎖.因此解決死鎖主要仍是真對於最經常使用的InnoDB. 遇到死鎖的處理方式負載均衡

mysql -uxxx -pxxx -h服務器ip --port=服務器端口;(若是服務器設置了ip和端口訪問的話,必定要帶ip和端口)函數

mysql> show processlist; #查看正在執行的sql (show full processlist;查看所有sql) mysql> kill id #殺死sql進程; 若是進程太多找不到,就重啓mysql吧 /ect/init.d/mysql restart 或/ect/init.d/mysql stop(若是關不掉就直接kill -9 進程id) 再/ect/init.d/mysql start 去看看mysql日誌文件是否保存死鎖日誌: 經常使用目錄:/var/log/mysqld.log;(該目錄還有其它相關日誌文件就都看看) 怎麼解決仍是要看具體什麼問題高併發

相關文章
相關標籤/搜索