MySQL鎖機制:不同的存儲引擎支持不同的鎖機制。
- 表級鎖:開銷小、加鎖快;不會出現死鎖;鎖粒度大,發生鎖衝突的概率高,併發度低。
- 頁面鎖:性能和併發性都介於表級鎖和行級鎖之間。
- 行級鎖:開銷大、加鎖慢;會出現死鎖;鎖粒度小,發生鎖衝突的概率低,併發度高。
由於鎖的特點不同,不同的鎖機制適合不同的應用:
a. 表級鎖適合於以查詢爲主,只有少量按照索引更新的應用,如web應用。
b. 行級鎖適合於有大量按索引條件併發更新少量不同數據,同時又有併發查詢的應用。
MyISQM表鎖:
table_locks_waited狀態變量表示不能立即加鎖,需要等待鎖的次數,也就意味着鎖等待。
table_locks_immediate狀態變量表示可以立即獲得鎖的次數
table_locks_waited/table_locks_immediate值越高說明數據庫的併發性越低,當該值達到一定程度,改用InnoDB存儲引擎。
MySQL MyISAM的表鎖:表共享讀鎖和表獨佔寫鎖
對MyISAM表的讀操作不會阻塞其他用戶對錶的讀請求,但是會阻塞對MyISAM表的寫請求;對MyISAM表的寫操作會阻塞其他用戶對錶的讀請求和寫請求。
MyISAM在執行查詢語句(select)前會自動給所有涉及的表加表共享讀鎖,在執行更新操作(update、delete、insert)前會自動給所有涉及的表加表獨佔寫鎖。
顯式加鎖:
讀鎖:lock table t read;
或者
lock table t read local;
寫鎖:lock table t write;
因爲MySQL不支持鎖升級,加鎖時需要取得所有涉及表的表鎖,所以加鎖之後,此會話在釋放鎖之前只能操作被加鎖的表,這就是爲什麼MyISAM的表鎖不會出現死鎖。
此外,如果對錶加讀鎖,當前用戶只能對鎖定表執行查詢(select)語句,其他用戶可以對錶加讀鎖,但是不可以對此表加寫鎖,也就是說只能對該表查詢(select),不能更新(update、insert 、delete);如果對錶加寫鎖,當前用戶可以對鎖定的表做任何操作,其他用戶不可以對此表加任何鎖,也就是說不可以對該表執行任何(select、update、insert、delete )操作。
MyISAM表下lock table t read和lock table t read local的區別:
當前對話lock table t read local後,根據concurrent_insert參數的值決定其他用戶可不可以併發插入。但是如果可以動態插入,不會影響當前對話的查詢結果。
concurrent_insert參數:
值爲0:不允許併發插入
值爲1:如果MyISAM表中沒有空洞(表的中間沒有被刪的行),允許在表尾併發插入
值爲2:不論有沒有空洞都允許在表尾併發插入
MyISAM的鎖調度:
MyISAM中,寫進程比讀進程會優先獲得鎖,從而可能到出現大量的更新操作使得查詢操作很難獲得讀鎖,造成讀進程餓死,同樣如果正在執行一個耗時的查詢操作,也可能出現寫進程餓死的情況。
解決方法:
1 》通過設置調度行:
通過制定insert、update、delete語句的low_priority屬性,調整更新語句的優先級。
2 》通過給系統參數max_write_lock_count設置一個合適的值,當一個表的讀鎖達到這個值後,MySQL就會降低寫鎖請求的優先級,給讀進程獲得資源的機會。
3 》將複雜的SQL查詢語句分解爲若干個耗時較小的SQL語句。