(該文章爲方便本身查閱,也但願對你們有所幫助,轉載於互聯網)
一、 鎖機制
當前MySQL支持
ISAM
,
MyISAM, MEMORY (HEAP) 類型表的
表級鎖,
BDB 表支持
頁級鎖,
InnoDB 表支持
行級鎖。
不少時候,能夠經過經驗來猜想什麼樣的鎖對應用程序更合適,不過一般很難說一個鎖比別的更好,這全都要依據應用程序來決定,不一樣的地方可能須要不一樣的鎖。
想要決定是否須要採用一個支持
行級鎖的存儲引擎,就要看看應用程序都要作什麼,其中的查詢、更新語句是怎麼用的。例如,
不少的web應用程序大量的作查詢,不多刪除,主要是基於索引的更新,只往特定的表中插入記錄。採用基本的MySQL的
MyISAM 表就很合適了。
MySQL中對錶級鎖的存儲引擎來講是釋放死鎖的。避免死鎖能夠這樣作到:在任何查詢以前先請求鎖,而且按照請求的順序鎖表。
1)MySQL中用於 WRITE(寫) 的表鎖的實現機制以下:
若是表沒有加鎖,那麼就加一個寫鎖。
不然的話,將請求放到寫鎖隊列中。
2)MySQL中用於 READ(讀) 的表鎖的實現機制以下:
若是表沒有加寫鎖,那麼就加一個讀鎖。
不然的話,將請求放到讀鎖隊列中。
當鎖釋放後,寫鎖隊列中的線程能夠用這個鎖資源,而後才輪到讀鎖隊列中的線程程。
這就是說,若是表裏有不少更新操做的話,那麼 Select 必須等到全部的更新都完成了以後才能開始。
如今版本的MySQL能夠經過狀態變量table_locks_waited 和table_locks_immediate 來分析系統中的鎖表爭奪狀況:
mysql> show status like 'table%';
+-----------------------+----------+
| Variable_name | Value |
+-----------------------+----------+
| Table_locks_immediate | 15184994 |
| Table_locks_waited | 20108 |
+-----------------------+----------+
2 rows in set (0.00 sec)
在 MySQL 3.23.7(在Windows上是3.23.25)之後,在 MyISAM 表中只要沒有衝突的Insert 操做,就能夠無需使用鎖表自由地並行執行Insert 和Select 語句。也就是說,能夠在其它客戶端正在讀取MyISAM 表記錄的同時時插入新記錄。若是數據文件的中間沒有空餘的磁盤塊的話,就不會發生衝突了,由於這種狀況下全部的新記錄都會寫在數據文件的末尾(當在表的中間作刪除或者更新操做時,就可能致使空洞)。當空洞被新數據填充後,並行插入特性就會自動從新被啓用了。
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 使用行級鎖,BDB 使用頁級鎖。對於 InnoDB 和 BDB 存儲引擎來講,是可能產生死鎖的。這是由於 InnoDB 會自動捕獲行鎖,BDB 會在執行 SQL 語句時捕獲頁鎖的,而不是在事務的開始就這麼作。
行級鎖的優勢有: (innodb)
在不少線程請求不一樣記錄時減小衝突鎖。
事務回滾時減小改變數據。
使長時間對單獨的一行記錄加鎖成爲可能。
行級鎖的缺點有:
比頁級鎖和表級鎖消耗更多的內存。
當在大量表中使用時,比頁級鎖和表級鎖更慢,由於他須要請求更多的鎖資源。
當須要頻繁對大部分數據作GROUP BY 操做或者須要頻繁掃描整個表時,就明顯的比其它鎖更糟糕。
-----------------------------------------------------------------------------------------
使用更高層的鎖的話,就能更方便的支持各類不一樣的類型應用程序,由於這種鎖的開銷比行級鎖小多了。
表級鎖在下列幾種狀況下比頁級鎖和行級鎖更優越:
不少操做都是讀表。
在嚴格條件的索引上讀取和更新,當更新或者刪除能夠用單獨的索引來讀取獲得時:
Update tbl_name SET column=value Where unique_key_col=key_value;
Delete FROM tbl_name Where unique_key_col=key_value;
Select 和 Insert 語句併發的執行,可是隻有不多的 Update 和 Delete 語句。
不少的掃描表和對全表的 GROUP BY 操做,可是沒有任何寫表。
二、 鎖表
爲了能有快速的鎖,MySQL除了 InnoDB 和 BDB 這兩種存儲引擎外,全部的都是用表級鎖(而非頁、行、列級鎖)。
對於 InnoDB 和 BDB 表,MySQL只有在指定用 LOCK TABLES 鎖表時才使用表級鎖。在這兩種表中,建議最好不要使用 LOCK TABLES,由於 InnoDB 自動採用行級鎖,BDB 用頁級鎖來保證事務的隔離。
若是數據表很大,那麼在大多數應用中表級鎖會比行級鎖好多了,不過這有一些陷阱。
表級鎖讓不少線程能夠同時從數據表中讀取數據,可是若是另外一個線程想要寫數據的話,就必需要先取得排他訪問。正在更新數據時,必需要等到更新完成了,其餘線程才能訪問這個表。
更新操做一般認爲比讀取更重要,所以它的優先級更高。不過最好要先確認,數據表是否有很高的 Select 操做,而更新操做並不是很‘急需’。
表鎖鎖在一個線程在等待,由於磁盤空間滿了,可是卻須要有空餘的磁盤空間,這個線程才能繼續處理時就有問題了。這種狀況下,全部要訪問這個出問題的表的線程都會被置爲等待狀態,直到有剩餘磁盤空間了。
表鎖在如下設想狀況中就不利了:
一個客戶端提交了一個須要長時間運行的 Select 操做。
其餘客戶端對同一個表提交了 Update 操做,這個客戶端就要等到 Select 完成了才能開始執行。
其餘客戶端也對同一個表提交了 Select 請求。因爲 Update 的優先級高於 Select,因此 Select 就會先等到 Update 完成了以後纔開始執行,它也在等待第一個 Select 操做。
下列所述能夠減小表鎖帶來的資源爭奪:
讓 Select 速度儘可能快,這可能須要建立一些摘要表。
啓動 mysqld 時使用參數 --low-priority-updates。這就會讓更新操做的優先級低於 Select。這種狀況下,在上面的假設中,第二個 Select 就會在 Insert 以前執行了,並且也無需等待第一個Select 了。
能夠執行 SET LOW_PRIORITY_UpdateS=1 命令,指定全部的更新操做都放到一個指定的連接中去完成。
用 LOW_PRIORITY 屬性來下降 Insert,Update,Delete 的優先級。
用 HIGH_PRIORITY 來提升 Select 語句的優先級。
從MySQL 3.23.7 開始,能夠在啓動 mysqld 時指定系統變量 max_write_lock_count 爲一個比較低的值,它能強制臨時地提升表的插入數達到一個特定值後的全部 Select 操做的優先級。它容許在 WRITE 鎖達到必定數量後有 READ 鎖。
當 Insert 和 Select 一塊兒使用出現問題時,能夠轉而採用 MyISAM 表,它支持併發的Select 和 Insert 操做。
當在同一個表上同時有插入和刪除操做時,Insert DELAYED 可能會頗有用。
當 Select 和 Delete 一塊兒使用出現問題時,Delete 的 LIMIT 參數可能會頗有用。
執行 Select 時使用 SQL_BUFFER_RESULT 有助於減短鎖表的持續時間.
如下是MySQL鎖的一些建議: 只要對同一個表沒有大量的更新和查詢操做混在一塊兒,目前的用戶並非問題。 執行 LOCK TABLES 來提升速度(不少更新操做放在一個鎖之中比沒有鎖的不少更新快多了)。將數據拆分開到多個表中可能也有幫助。 當MySQL碰到因爲鎖表引發的速度問題時,將表類型轉換成 InnoDB 或 BDB 可能有助於提升性能。