1. 程式人生 > 其它 >萬答#1,MySQL中如何查詢某個表上的IS(意向共享)鎖

萬答#1,MySQL中如何查詢某個表上的IS(意向共享)鎖

歡迎來到 GreatSQL社群分享的MySQL技術文章,如有疑問或想學習的內容,可以在下方評論區留言,看到後會進行解答

問題

問題原文是這樣的:

假如在MySQL事務裡,給某個表的一行加了 共享鎖,理論上這個表本身會自動加上意向共享鎖,那麼能不能用 sql 查出這個表加了意向鎖?

回答

答案是肯定的,當然可以執行SQL查詢表上的IS鎖加鎖狀態。

先宣告,我們本次討論的是MySQL裡的InnoDB引擎表,下面討論的內容都是基於這個前提。

在揭曉答案之前,多介紹點InnoDB引擎鎖相關的一些知識吧。主要有以下幾點

  • InnoDB引擎表既支援表級鎖,也支援行級鎖。

  • 加表級鎖的方法和MyISAM表是一樣的,執行 LOCK TABLE READ/WRITE 即可。

  • InnoDB表的行鎖是加在索引上的,因此如果沒有合適的索引,是會導致表裡所有記錄都被加上行鎖,其後果等同於表級鎖,但產生的影響比表級鎖可就大多了。因為鎖物件數量大了很多,消耗的記憶體也多很多。

  • 加上行鎖時,同時還需要對錶加上相應的意向鎖。例如,想要對一行資料加上共享鎖(S鎖),則相應的要對錶加上意向共享鎖(IS鎖);同樣地,想要對一行資料加上排他鎖(X鎖),則相應的要對錶加上意向排他鎖(IX鎖)。

  • 意向鎖是加在聚集索引的根節點上的,因此無論鎖定多少行,只需要加一個意向鎖。

  • 下面是幾個鎖之間的相容矩陣

好了,接下來我們來看下怎麼查看錶級IS鎖。其實很簡單,只需要檢視 PFS.data_locks 表就可以了。另一個表 PFS.metadata_locks 表可以檢視MDL鎖的詳情。

查詢結果例如下面這樣:

[[email protected]] [(none)]>select * from performance_schema.data_locks\G
*************************** 1. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 140701134495048:1350:140701396637648
ENGINE_TRANSACTION_ID: 422176111205704
            THREAD_ID: 87
             EVENT_ID: 95
        OBJECT_SCHEMA: yejr
          OBJECT_NAME: t1
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140701396637648
            LOCK_TYPE: TABLE
            LOCK_MODE: IS
          LOCK_STATUS: GRANTED
            LOCK_DATA: NULL
*************************** 2. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 140701134495048:267:4:9:140701409130528
ENGINE_TRANSACTION_ID: 422176111205704
            THREAD_ID: 87
             EVENT_ID: 95
        OBJECT_SCHEMA: yejr
          OBJECT_NAME: t1
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 140701409130528
            LOCK_TYPE: RECORD
            LOCK_MODE: S,REC_NOT_GAP
          LOCK_STATUS: GRANTED
            LOCK_DATA: 1

此時我們能看到t1表上共有兩個鎖,一個是表級IS鎖,另一個是c1=1上的共享鎖。

同樣地,我們也可以觀察IX鎖或其他鎖。

- session1執行下面的SQL
[[email protected]] [yejr]>begin; update t1 set c4=rand()*1024 where c1=1;

- session2查詢PFS.data_locks
[[email protected]] [(none)]>select * from performance_schema.data_locks\G
*************************** 1. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 140701134495888:1350:140701396639728
ENGINE_TRANSACTION_ID: 104536
            THREAD_ID: 89
             EVENT_ID: 43
        OBJECT_SCHEMA: yejr
          OBJECT_NAME: t1
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140701396639728
            LOCK_TYPE: TABLE
            LOCK_MODE: IX  <-- 這個就是IX鎖了
          LOCK_STATUS: GRANTED
            LOCK_DATA: NULL
*************************** 2. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 140701134495888:267:4:9:140701409135136
ENGINE_TRANSACTION_ID: 104536
            THREAD_ID: 89
             EVENT_ID: 43
        OBJECT_SCHEMA: yejr
          OBJECT_NAME: t1
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 140701409135136
            LOCK_TYPE: RECORD
            LOCK_MODE: X,REC_NOT_GAP
          LOCK_STATUS: GRANTED
            LOCK_DATA: 1

進一步,我們簡單看下MDL鎖。加共享行鎖:

- session1加一個共享行鎖
[[email protected]] [yejr]>begin; select * from t1 where c1=1 for share;

- session2查詢表上有哪些MDL鎖
[[email protected]] [(none)]>select * from performance_schema.metadata_locks\G
*************************** 1. row ***************************
          OBJECT_TYPE: TABLE
        OBJECT_SCHEMA: yejr
          OBJECT_NAME: t1
          COLUMN_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140701215694512
            LOCK_TYPE: SHARED_READ  <- 共享讀鎖,可以同時加多個共享行鎖
        LOCK_DURATION: TRANSACTION
          LOCK_STATUS: GRANTED
               SOURCE: sql_parse.cc:5761
      OWNER_THREAD_ID: 87
       OWNER_EVENT_ID: 100

也看下加排他行鎖:

- session1加一個排他行鎖
[[email protected]] [yejr]>begin; update t1 set c4=rand()*1024 where c1=1;

- session2查詢表上有哪些MDL鎖
[[email protected]] [(none)]>select * from performance_schema.metadata_locks\G
*************************** 1. row ***************************
          OBJECT_TYPE: TABLE
        OBJECT_SCHEMA: yejr
          OBJECT_NAME: t1
          COLUMN_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140701215694640
            LOCK_TYPE: SHARED_WRITE  <- 共享寫鎖,可以同時加多個排他行鎖(不同資料行)
        LOCK_DURATION: TRANSACTION
          LOCK_STATUS: GRANTED
               SOURCE: sql_parse.cc:5761
      OWNER_THREAD_ID: 89
       OWNER_EVENT_ID: 43

好了,方法已有,更多的情形可以自己去玩了 :)

測試環境

Server version: 8.0.23 MySQL Community Server - GPL

上述PFS檢視行鎖、MDL鎖的功能應該是8.0以上就開始支援了。

Enjoy MySQL :)

文章推薦:

技術分享 | MGR最佳實踐(MGR Best Practice)
https://mp.weixin.qq.com/s/66u5K7a9u8GcE2KPn4kCaA

技術分享 | 萬里資料庫MGR Bug修復之路
https://mp.weixin.qq.com/s/IavpeP93haOKVBt7eO8luQ

Macos系統編譯percona及部分函式在Macos系統上運算差異
https://mp.weixin.qq.com/s/jAbwicbRc1nQ0f2cIa_2nQ

技術分享 | 利用systemd管理MySQL單機多例項
https://mp.weixin.qq.com/s/iJjXwd0z1a6isUJtuAAHtQ

產品 | GreatSQL,打造更好的MGR生態
https://mp.weixin.qq.com/s/ByAjPOwHIwEPFtwC5jA28Q

產品 | GreatSQL MGR優化參考
https://mp.weixin.qq.com/s/5mL_ERRIjpdOuONian8_Ow

關於 GreatSQL

GreatSQL是由萬里資料庫維護的MySQL分支,專注於提升MGR可靠性及效能,支援InnoDB並行查詢特性,是適用於金融級應用的MySQL分支版本。

Gitee:
https://gitee.com/GreatSQL/GreatSQL

GitHub:
https://github.com/GreatSQL/GreatSQL

微信&QQ群:

可掃碼新增GreatSQL社群助手微信好友,傳送驗證資訊“加群”加入GreatSQL/MGR交流微信群,亦可直接掃碼加入GreatSQL/MGR交流QQ群。

本文由部落格一文多發平臺 OpenWrite 釋出!