文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  ...  /  內部鎖定方法

10.11.1 內部鎖定方法

本節討論內部鎖定;也就是說,MySQL 伺服器本身為了管理多個工作階段對資料表內容的爭用而執行的鎖定。此類型的鎖定是內部鎖定,因為它完全由伺服器執行,不涉及其他程式。如需其他程式對 MySQL 檔案執行的鎖定,請參閱第 10.11.5 節「外部鎖定」

資料列層級鎖定

MySQL 對 InnoDB 資料表使用資料列層級鎖定,以支援多個工作階段同時寫入存取,使其適用於多使用者、高並發和 OLTP 應用程式。

為了避免在單一 InnoDB 資料表上執行多個並行寫入作業時發生死結,請在交易開始時,針對預期要修改的每一組資料列發出 SELECT ... FOR UPDATE 陳述式,取得必要的鎖定,即使資料變更陳述式是在交易中稍後才出現也是如此。如果交易修改或鎖定多個資料表,請在每個交易內以相同的順序發出適用的陳述式。死結會影響效能,但不會表示嚴重錯誤,因為 InnoDB 預設會自動偵測死結狀況,並回溯受影響的其中一個交易。

在高並發系統上,當大量執行緒等待相同的鎖定時,死結偵測可能會導致速度減慢。有時,在發生死結時停用死結偵測並依賴innodb_lock_wait_timeout 設定進行交易回溯可能會更有效率。可以使用 innodb_deadlock_detect 設定選項停用死結偵測。

資料列層級鎖定的優點

  • 當不同的工作階段存取不同的資料列時,鎖定衝突較少。

  • 回溯的變更較少。

  • 可以長時間鎖定單一資料列。

資料表層級鎖定

MySQL 對 MyISAMMEMORYMERGE 資料表使用資料表層級鎖定,一次只允許一個工作階段更新這些資料表。此鎖定層級使這些儲存引擎更適用於唯讀、大部分唯讀或單一使用者應用程式。

這些儲存引擎會藉由在查詢開始時永遠一次要求所有需要的鎖定,並永遠以相同的順序鎖定資料表來避免死結。取捨之道是,此策略會降低並發性;其他想要修改資料表的工作階段必須等到目前的資料變更陳述式完成。

資料表層級鎖定的優點

  • 需要的記憶體相對較少(資料列鎖定需要每個資料列或鎖定的資料列群組的記憶體)

  • 當在資料表的大部分使用時速度很快,因為只涉及單一鎖定。

  • 如果您經常對大部分資料執行 GROUP BY 作業,或必須經常掃描整個資料表,則速度很快。

MySQL 授予資料表寫入鎖定的方式如下

  1. 如果資料表上沒有鎖定,則對其放置寫入鎖定。

  2. 否則,將鎖定請求放入寫入鎖定佇列中。

MySQL 授予資料表讀取鎖定的方式如下

  1. 如果資料表上沒有寫入鎖定,則對其放置讀取鎖定。

  2. 否則,將鎖定請求放入讀取鎖定佇列中。

資料表更新的優先順序高於資料表檢索。因此,當鎖定釋放時,鎖定會先提供給寫入鎖定佇列中的請求,然後才提供給讀取鎖定佇列中的請求。這確保即使資料表有大量的 SELECT 活動,對資料表的更新也不會餓死。但是,如果資料表有很多更新,SELECT 語句會等待直到沒有更多更新。

如需關於變更讀取和寫入優先順序的資訊,請參閱第 10.11.2 節「資料表鎖定問題」

您可以透過檢查 Table_locks_immediateTable_locks_waited 狀態變數來分析系統上的資料表鎖定競爭,它們分別指示資料表鎖定請求可以立即獲得授權的次數以及必須等待的次數。

mysql> SHOW STATUS LIKE 'Table%';
+-----------------------+---------+
| Variable_name         | Value   |
+-----------------------+---------+
| Table_locks_immediate | 1151552 |
| Table_locks_waited    | 15324   |
+-----------------------+---------+

效能架構鎖定資料表也提供鎖定資訊。請參閱第 29.12.13 節「效能架構鎖定資料表」

MyISAM 儲存引擎支援並行插入,以減少給定資料表的讀取器和寫入器之間的競爭:如果 MyISAM 資料表在資料檔案中間沒有可用區塊,則資料列始終插入到資料檔案的末尾。在這種情況下,您可以自由地混合使用並行的 INSERTSELECT 語句,而無需對 MyISAM 資料表進行鎖定。也就是說,您可以在其他用戶端正在從 MyISAM 資料表讀取資料的同時,將資料列插入到該資料表中。資料表中間刪除或更新的資料列可能會導致出現空洞。如果有空洞,並行插入會被停用,但當所有空洞都填滿新資料時,會自動再次啟用。若要控制此行為,請使用 concurrent_insert 系統變數。請參閱第 10.11.3 節「並行插入」

如果您使用 LOCK TABLES 明確取得資料表鎖定,您可以請求 READ LOCAL 鎖定,而不是 READ 鎖定,以便在您鎖定資料表時,其他工作階段可以執行並行插入。

當無法進行並行插入時,若要在資料表 t1 上執行許多 INSERTSELECT 操作,您可以將資料列插入到臨時資料表 temp_t1 中,並使用臨時資料表中的資料列來更新實際資料表。

mysql> LOCK TABLES t1 WRITE, temp_t1 WRITE;
mysql> INSERT INTO t1 SELECT * FROM temp_t1;
mysql> DELETE FROM temp_t1;
mysql> UNLOCK TABLES;

選擇鎖定類型

一般而言,在以下情況下,資料表鎖定優於資料列級鎖定

  • 資料表的大部分語句都是讀取。

  • 資料表的語句是讀取和寫入的組合,其中寫入是針對可以使用一個索引鍵讀取來擷取的單一資料列進行更新或刪除

    UPDATE tbl_name SET column=value WHERE unique_key_col=key_value;
    DELETE FROM tbl_name WHERE unique_key_col=key_value;
  • SELECT 語句結合並行的 INSERT 語句,以及非常少的 UPDATEDELETE 語句。

  • 對整個資料表進行許多掃描或 GROUP BY 操作,而沒有任何寫入器。

使用較高層級的鎖定,您可以更輕鬆地透過支援不同類型的鎖定來調整應用程式,因為鎖定的額外負荷比資料列級鎖定要少。

資料列級鎖定以外的其他選項

  • 版本控制(例如 MySQL 用於並行插入的版本控制),其中可以有一個寫入器和多個讀取器同時存在。這表示資料庫或資料表根據存取開始的時間支援不同的資料檢視。其他常用的術語包括時間旅行寫入時複製隨需複製

  • 在許多情況下,隨需複製優於資料列級鎖定。但是,在最壞的情況下,它可能比使用一般鎖定使用更多的記憶體。

  • 您可以採用應用程式級鎖定,而不是使用資料列級鎖定,例如 MySQL 中 GET_LOCK()RELEASE_LOCK() 所提供的鎖定。這些是建議性的鎖定,因此它們僅適用於彼此協作的應用程式。請參閱第 14.14 節「鎖定函數」