performance_schema実用的なアプリケーション・ノート(3) - ブロックとロックのトラブルシューティング

グローバルリードロック、メタデータロック(MDL)、テーブルロック、行ロック - 最後に、共通のMySQLのシリーズは、ロック、ブロッキングの問題の4種類をご紹介します

 

まず、グローバルリードロック

グローバル読み込みロックは、通常、読み取りロックと同一平面表で、このような文を追加し、そのような文は、通常のバックアップツールのさまざまな一貫性のあるバックアップを取得します。あるいは、主スイッチング素子を使用しました。トラブルシューティングするために最も困難がある場合、オンラインシステムの権限の制約が標準化されていない場合は、様々なアカウントが権限を持っているRELOAD、読み取りロックがグローバルデータベースに追加することができます。 

グローバルリードロックを保持してトラブルシューティングする前のMySQL 5.7へのバージョンでは、(innodb_locksテーブルロックが唯一のデータベースのInnoDB層レベルでの情報を記録することができ、およびグローバルリードロックは、ロックサーバ層ではない、多くの場合、有用なデータへの直接クエリすることは困難です問い合わせ対象)、5.7から表performance_schema.metadata_locksテーブルの提供を開始しました()グローバルリードロックとロックMDLを含むロックサーバの情報層の一部を記録します。

 

のは、例を通じてperformance_schemaを使用してグローバルリードロックを保持している人を見つけるしてみましょう。

まず、最初のセッション、グローバルリードロックの実装を開きます。

-- 执行加锁语句
flush table with read lock;
Query OK, 0 rows affected (0.00 sec)

-- 查询加锁线程的process id,后续排查过程好对应
root@localhost : sbtest 12:31:48> select connection_id();
+-----------------+
| connection_id() |
+-----------------+
| 4 |
+-----------------+
1 row in set (0.00 sec)

一例として、更新操作に対して任意のDMLステートメントを実行するために第2のセッションを開きます。

-- 测试查询
select * from sbtest1 limit 1\G;
*************************** 1. row ***************************
id: 21
k: 2483476
c: 09279210219-37745839908-56185699327-79477158641-86711242956-61449540392-42622804506-61031512845-36718422840-11028803849
pad: 96813293060-05308009118-09223341195-19224109585-45598161848
1 row in set (0.00 sec)
ERROR: 
No query specified

-- 记下线程id
select connection_id();
+-----------------+
| connection_id() |
+-----------------+
| 5 |
+-----------------+
1 row in set (0.00 sec)

-- 测试更新
update sbtest1 set pad='xxx' where id=21;  -- 操作被阻塞

調査のため、第三セッションを開きます。

select connection_id();
+-----------------+
| connection_id() |
+-----------------+
| 16 |
+-----------------+
1 row in set (0.00 sec)

-- 查询processlist信息,只能看到processid为5的线程State为Waiting for global read lock,表示正在等待全局读锁
show processlist;
+----+-------+---------------------+--------+-------------+-------+---------------------------------------------------------------+------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-------+---------------------+--------+-------------+-------+---------------------------------------------------------------+------------------------------------------+
| 3 | qfsys | 192.168.2.168:41042 | NULL | Binlog Dump | 11457 | Master has sent all binlog to slave; waiting for more updates | NULL |
| 4 | root | localhost | sbtest | Sleep | 234 | | NULL |
| 5 | root | localhost | sbtest | Query | 26 | Waiting for global read lock | update sbtest1 set pad='xxx' where id=21 |
| 16 | root | localhost | NULL | Query | 0 | starting | show processlist |
+----+-------+---------------------+--------+-------------+-------+---------------------------------------------------------------+------------------------------------------+
4 rows in set (0.00 sec)

-- 查询information_schema.innodb_locks、innodb_lock_waits、innodb_trx表,发现三个表均为空(因为全局读锁不是InnoDB层而是Server层的锁)
select * from information_schema.innodb_locks;
Empty set, 1 warning (0.00 sec)
select * from information_schema.innodb_lock_waits;
Empty set, 1 warning (0.00 sec)
select * from information_schema.innodb_trx\G
Empty set (0.00 sec)

-- 再使用show engine innodb status;查看一把(只需要看TRANSACTION段落即可),仍然无任何有用的锁信息
root@localhost : (none) 12:59:48> show engine innodb status;
......
------------
TRANSACTIONS
------------
Trx id counter 2527502
Purge done for trx's n:o < 2527500 undo n:o < 0 state: running but idle
History list length 3
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 422099353083504, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 422099353082592, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 422099353081680, not started
0 lock struct(s), heap size 1136, 0 row lock(s)

、任意の有用な情報なしにこのダウンタイムを照会する従来の手段によって、経験豊富なベテランのデバッグ推定GDBは、GDB、straceの、どのようなMySQLのコマンドコールスタックを表示するには、どのようなスレッド情報ではなく、C言語用のpstackを使用して開始されますがあります人々、基本的には象形文字の基本。

我々がしよう下回る5.7バージョンからは、さまざまなサーバーのperformance_schema.metadata_locksテーブルロック情報記録層、クエリテーブルが用意されています。

-- 持锁会话通常有两个(但为同一个线程),特征如下:OBJECT_TYPE为global和commit、LOCK_TYPE为SHARED

select * from performance_schema.metadata_locks where OWNER_THREAD_ID!=sys.ps_thread_id(connection_id())\G;

*************************** 1. row ***************************
      OBJECT_TYPE: GLOBAL <---
    OBJECT_SCHEMA: NULL
      OBJECT_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140621322913984
        LOCK_TYPE: SHARED  # 共享锁
    LOCK_DURATION: EXPLICIT  # 显式
      LOCK_STATUS: GRANTED  # 已授予
           SOURCE: lock.cc:1110
  OWNER_THREAD_ID: 94 # 持有锁的内部线程ID为94
   OWNER_EVENT_ID: 16  

*************************** 2. row ***************************
      OBJECT_TYPE: COMMITL <---
    OBJECT_SCHEMA: NULL
      OBJECT_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140621322926064
        LOCK_TYPE: SHARED # 共享锁
    LOCK_DURATION: EXPLICIT  # 显式
      LOCK_STATUS: GRANTED # 已授予
           SOURCE: lock.cc:1194
  OWNER_THREAD_ID: 94  # 持有锁的内部线程ID为94
   OWNER_EVENT_ID: 16  

*************************** 3. row ***************************
      OBJECT_TYPE: GLOBAL
    OBJECT_SCHEMA: NULL
      OBJECT_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140621391527216
        LOCK_TYPE: INTENTION_EXCLUSIVE  # 意向排它锁
    LOCK_DURATION: STATEMENT  # 语句
      LOCK_STATUS: PENDING  # 状态为pending,等待锁授予(正在被阻塞)
           SOURCE: sql_base.cc:3190
  OWNER_THREAD_ID: 95  # 被阻塞的内部线程ID为95
   OWNER_EVENT_ID: 38 
3 rows in set (0.00 sec)

-- 查看process id为4,5 各自对应的内部线程ID是多少
select sys.ps_thread_id(4);
+---------------------+
| sys.ps_thread_id(4) |
+---------------------+
| 94 |    # process id=4的线程对应的内部线程ID正好为94,说明就是process id=4的线程持有了全局读锁
+---------------------+
1 row in set (0.00 sec)

select sys.ps_thread_id(5);
+---------------------+
| sys.ps_thread_id(5) |
+---------------------+
| 95 |   # proces id=5的线程对应的内部线程正好是95,说明在等待全局读锁的就是process id=5的线程
+---------------------+
1 row in set (0.00 sec)

本番環境ならば、これらはすべてPROCESSLIST情報に対応するプロセスID = 4行は、明確化のために関係者を見つけるために、主にどのようなビジネス上の目的に属しているかを決定、ユーザー、ホスト、DB情報にキルを発見したショーで撮影されましたこの問題を回避する方法を将来に道を下に議論するために、殺すために。

 

第二には、MDLロックを保持している人を見つけます

- > DDL文の/バックアップを実行する - 読み取りおよび書き込み操作を実行する>他のセッション、メタデータロック待ちを待っている多数の大規模なクエリ/コミットされていない大規模なトランザクションを実行します。この問題は、一般的です。

後にのこぎりSYSシステムライブラリがschema_table_lock_wait(5.7.9新しい)ビューを持っている、あなたは情報を待っているMDLを簡単に表示することができます説明します。そのデータソースがスレッド、metadata_locks、performance_schema下events_statements_currentテーブルがわかります。このビューの定義を参照してください。我々はperformance_schema下MDL長期使用のテーブルロックを保持している人を見つける方法これが最初。

 

消費者のperformance_schema.metadata_locksに対応し、デフォルトでは有効になっていない、ロック/メタデータ/ SQL / MDL /待機するように対応したMDLロック記録機器、唯一のグローバルコンフィギュレーション項目global_instrumentation制御によるsetup_consumersは、デフォルトで有効になって。

UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'wait/lock/metadata/sql/mdl';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
  
select * from performance_schema.setup_instruments WHERE NAME = 'wait/lock/metadata/sql/mdl';
 
+----------------------------+---------+-------+
| NAME                       | ENABLED | TIMED |
+----------------------------+---------+-------+
| wait/lock/metadata/sql/mdl | YES     | NO    |
+----------------------------+---------+-------+
1 row in set (0.00 sec)

まず、次のステートメントを実行し、それぞれ、二つのセッションを開きます。

-- 会话1,显式开启一个事务,并执行一个update语句更新sbtest1表不提交
begin;
Query OK, 0 rows affected (0.00 sec)

update sbtest1 set pad='yyy' where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

-- 会话2,对sbtest1表执行DDL语句添加一个普通索引
alter table sbtest1 add index i_c(c);  -- 被阻塞

また、クエリスレッド情報にショーPROCESSLISTステートメントを使用して、セッション3を開くには、更新ステートメントは、(テーブルのメタデータロック待ち)MDLロックを待っている見つけることができます。

show processlist;
+----+------+-----------+--------+---------+------+---------------------------------+--------------------------------------+
| Id | User | Host      | db    | Command | Time | State                          | Info                                |
+----+------+-----------+--------+---------+------+---------------------------------+--------------------------------------+
| 92 | root | localhost | sbtest | Query  |  121 | Waiting for table metadata lock | alter table sbtest1 add index i_c(c) |
| 93 | root | localhost | NULL  | Query  |    0 | starting                        | show processlist                    |
| 94 | root | localhost | sbtest | Sleep  | 1078 |                                | NULL                                |
+----+------+-----------+--------+---------+------+---------------------------------+--------------------------------------+
3 rows in set (0.00 sec)

表ビューのクエリperformance_schema.metadata_locksは、MDL情報をロック

root@localhost : (none) 01:23:05> select * from performance_schema.metadata_locks where OWNER_THREAD_ID!=sys.ps_thread_id(connection_id())\G;
*************************** 1. row ***************************
      OBJECT_TYPE: TABLE
    OBJECT_SCHEMA: sbtest
      OBJECT_NAME: sbtest1
OBJECT_INSTANCE_BEGIN: 139886013386816
        LOCK_TYPE: SHARED_WRITE
    LOCK_DURATION: TRANSACTION
      LOCK_STATUS: GRANTED
          SOURCE: sql_parse.cc:5996
  OWNER_THREAD_ID: 136
  OWNER_EVENT_ID: 721

*************************** 2. row ***************************
      OBJECT_TYPE: GLOBAL
    OBJECT_SCHEMA: NULL
      OBJECT_NAME: NULL
OBJECT_INSTANCE_BEGIN: 139886348911600
        LOCK_TYPE: INTENTION_EXCLUSIVE
    LOCK_DURATION: STATEMENT
      LOCK_STATUS: GRANTED
          SOURCE: sql_base.cc:5497
  OWNER_THREAD_ID: 134
  OWNER_EVENT_ID: 4667

*************************** 3. row ***************************
      OBJECT_TYPE: SCHEMA
    OBJECT_SCHEMA: sbtest
      OBJECT_NAME: NULL
OBJECT_INSTANCE_BEGIN: 139886346748096
        LOCK_TYPE: INTENTION_EXCLUSIVE
    LOCK_DURATION: TRANSACTION
      LOCK_STATUS: GRANTED
          SOURCE: sql_base.cc:5482
  OWNER_THREAD_ID: 134
  OWNER_EVENT_ID: 4667

*************************** 4. row ***************************
      OBJECT_TYPE: TABLE
    OBJECT_SCHEMA: sbtest
      OBJECT_NAME: sbtest1
OBJECT_INSTANCE_BEGIN: 139886346749984
        LOCK_TYPE: SHARED_UPGRADABLE
    LOCK_DURATION: TRANSACTION
      LOCK_STATUS: GRANTED
          SOURCE: sql_parse.cc:5996
  OWNER_THREAD_ID: 134
  OWNER_EVENT_ID: 4669

*************************** 5. row ***************************
      OBJECT_TYPE: TABLE
    OBJECT_SCHEMA: sbtest
      OBJECT_NAME: sbtest1
OBJECT_INSTANCE_BEGIN: 139886348913168
        LOCK_TYPE: EXCLUSIVE
    LOCK_DURATION: TRANSACTION
      LOCK_STATUS: PENDING  <-- 被阻塞者
          SOURCE: mdl.cc:3891
  OWNER_THREAD_ID: 134
  OWNER_EVENT_ID: 4748
5 rows in set (0.00 sec)

我々は、5行MDLロックレコード、テーブルsbtest.sbtest1 SHARED_WRITEロックの最初の行を発見した(プロセスID 94に対応)は、スレッド136を保持し、状態が付与されます。(プロセスID 92に対応)は、スレッド134を保持し、保留状態のSHARED_UPGRADABLE状態、EXCLUSIVEが付与され、後続の行4、そこSHARED_UPGRADABLE sbtest.sbtest1テーブル、EXCLUSIVEロック、スレッド134は、MDLがロックを説明待機しています。

上記のデータを通じて、我々はMDL 136のスレッドがロックを保持していることを知って、クエリ結果を通して見ることができるがスリープ状態で長い時間となっているスレッド94のPROCESSLISTステートメントプロセスIDを示しており、このスレッドは、文を実行ものを見ることができません。

トランザクションのスレッドの存在を確認、それをinformation_schema.innodb_trxテーブルをチェックする必要は提出しませんでした。テーブルは、プロセスIDスレッド94(trx_mysql_thread_id = 94)を照会することにより発見されたコミットされていないトランザクションを持っているが、多くの有用な情報がありません。

select * from information_schema.innodb_trx\G;

*************************** 1. row ***************************
                trx_id: 2452892
            trx_state: RUNNING
          trx_started: 2018-01-14 01:19:25 <-- 事务开始时间
trx_requested_lock_id: NULL
      trx_wait_started: NULL
            trx_weight: 3
  trx_mysql_thread_id: 94  <-- 线程id
......
1 row in set (0.00 sec)

トランザクションが原因MDL 134スレッドロック待ちが発生するスレッド136を提出しなかったが、136スレッドが何をしているのか分からないことが知られているが。スレッドは134をダウン継続するように、我々は確かに136スレッドを殺すことができますが、あなたはどのような136スレッドの実行文がわからない場合、あなたは、最適化するために、再度同様の問題が発生することがあり、次の時間を、開発者を見つけることができません。

また、実行しているスレッドを照会するperformance_schema.events_statements_currentイベント情報テーブルや、スレッドごとにテーブルが現在実行し、ごく最近の実装いったん記録ので、情報は必ずしも信頼できない最後の実行完了を(することができます完全なイベント情報声明、このスレッドは新しいステートメントを実行すると、情報がカバーされます):

select * from performance_schema.events_statements_current where thread_id=136\G;

*************************** 1. row ***************************
          THREAD_ID: 136
          EVENT_ID: 715
      END_EVENT_ID: 887
        EVENT_NAME: statement/sql/update
            SOURCE: socket_connection.cc:101
......
          SQL_TEXT: update sbtest1 set pad='yyy' where id=1
            DIGEST: 69f516aa8eaa67fd6e7bfd3352de5d58
        DIGEST_TEXT: UPDATE `sbtest1` SET `pad` = ? WHERE `id` = ? 
    CURRENT_SCHEMA: sbtest
.....
1 row in set (0.00 sec)

SQL_TEXTフィールドによってテーブルからPerformance_schema.events_statements_currentクエリ情報は、我々は、スレッドがはい実行されていることをどのようなSQL文を見ることができます。本番環境ならば、今、あなたは同様の文が同様の問題に次の時間を避けるために、時間内に提出しなければならない、次の出会いを、関連する開発者の表現を見つけることができます。

 

第三に、テーブルロックを保持している人を見つけます

唯一のグローバル設定項目global_instrumentation制御によるsetup_consumers、消費者のperformance_schema.table_handlesに対応し、デフォルトで有効になって(待機/ロック/テーブル/ SQL /ハンドラ)の楽器を、対応する表ロックは、デフォルトで有効になって。したがってperformance_schema = ONは、デフォルトで設定することができます。ここでは、テーブルのロックを保持している人を見つける方法の例では示しています。

まず、二つのセッションを開いて、最初のセッションは、テーブルの上に明示的なテーブルロックを追加し、第2の操作セッションDML文は、テーブルに対して実行されます

-- 会话1加表级锁
select connection_id();
+-----------------+
| connection_id() |
+-----------------+
| 18 |
+-----------------+
1 row in set (0.00 sec)

lock table sbtest1 read;
Query OK, 0 rows affected (0.00 sec)

-- 会话2对该表执行update更新
select connection_id();
+-----------------+
| connection_id() |
+-----------------+
| 19 |
+-----------------+
1 row in set (0.00 sec)

update sbtest1 set pad='xxx' where id=1; -- 被阻塞

第三セッションを開き、クエリスレッド情報にショーPROCESSLISTステートメントを使用して、更新ステートメントは、MDLをロックするために待っている見つけます

root@localhost : (none) 02:40:14> show processlist;
+----+-------+---------------------+--------+-------------+-------+---------------------------------------------------------------+-----------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-------+---------------------+--------+-------------+-------+---------------------------------------------------------------+-----------------------------------------+
| 3 | qfsys | 192.168.2.168:41042 | NULL | Binlog Dump | 18565 | Master has sent all binlog to slave; waiting for more updates | NULL |
| 18 | root | localhost | sbtest | Sleep | 67 | | NULL |
| 19 | root | localhost | sbtest | Query | 51 | Waiting for table metadata lock | update sbtest1 set pad='xxx' where id=1 |
| 20 | root | localhost | NULL | Query | 0 | starting | show processlist |
+----+-------+---------------------+--------+-------------+-------+---------------------------------------------------------------+-----------------------------------------+
4 rows in set (0.00 sec)

それは調査の段階で、その上にMDLロックを待機しているので、問い合わせperformance_schema.metadata_locksテーブル、と思うかもしれないロックを代表して、レコードの順序は時系列順に保持されています

select * from performance_schema.metadata_locks where OWNER_THREAD_ID!=sys.ps_thread_id(connection_id())\G;

*************************** 1. row ***************************
      OBJECT_TYPE: TABLE
    OBJECT_SCHEMA: sbtest
      OBJECT_NAME: sbtest1
OBJECT_INSTANCE_BEGIN: 140622530920576
        LOCK_TYPE: SHARED_READ_ONLY
    LOCK_DURATION: TRANSACTION
      LOCK_STATUS: GRANTED
           SOURCE: sql_parse.cc:5996
  OWNER_THREAD_ID: 113  -- 内部ID为113的线程被授予SHARED_READ_ONLY锁,持有该锁的线程不允许其他线程修改sbtest1表的数据
   OWNER_EVENT_ID: 11

*************************** 2. row ***************************
      OBJECT_TYPE: GLOBAL
    OBJECT_SCHEMA: NULL
      OBJECT_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140620517607728
        LOCK_TYPE: INTENTION_EXCLUSIVE
    LOCK_DURATION: STATEMENT
      LOCK_STATUS: GRANTED
           SOURCE: sql_base.cc:3190
  OWNER_THREAD_ID: 114  -- 内部ID为114的线程被授予锁INTENTION_EXCLUSIVE,即意向锁IX
   OWNER_EVENT_ID: 12

*************************** 3. row ***************************
      OBJECT_TYPE: TABLE
    OBJECT_SCHEMA: sbtest
      OBJECT_NAME: sbtest1
OBJECT_INSTANCE_BEGIN: 140620517607824
        LOCK_TYPE: SHARED_WRITE
    LOCK_DURATION: TRANSACTION
      LOCK_STATUS: PENDING
           SOURCE: sql_parse.cc:5996
  OWNER_THREAD_ID: 114  -- 内部ID为114的线程正在等待SHARED_WRITE锁被授予
   OWNER_EVENT_ID: 12
3 rows in set (0.00 sec)

調査は、我々は手術台のほとんどのための非常に一般的なMDLロックが(テーブルトップに記録された情報のperformance_schema.metadata_locksに応じてロックが使用されていない)テーブルの上に最初のプラスMDLロックになります知っている、失速しました。

この時点で、あなたは、いくつかのテーブルレベルのロックをチェックして、以下のperformance_schema .table_handlesテーブルを見つけることを試みること

select * from performance_schema.table_handles where OWNER_THREAD_ID!=0\G;

*************************** 1. row ***************************
      OBJECT_TYPE: TABLE
    OBJECT_SCHEMA: sbtest
      OBJECT_NAME: sbtest1
OBJECT_INSTANCE_BEGIN: 140622530923216
  OWNER_THREAD_ID: 113
   OWNER_EVENT_ID: 11
    INTERNAL_LOCK: NULL
    EXTERNAL_LOCK: READ EXTERNAL -- 发现内部ID为113的线程持有了sbtest1表的READ EXTERNAL表级锁,这也是内部ID为114的线程无法获取到MDL锁的原因
1 row in set (0.00 sec)  

関連データに上記のクエリによってわかるように、performance_schema.events_statements_currentすることができます、113スレッドsbtest1テーブルは、明示的にテーブルレベルのロックを読ん追加し、スリープ状態で長時間、私たちはそのスレッドがSQL文を実行しているかわかりません次のようにテーブル、クエリ、

select * from performance_schema.events_statements_current where thread_id=113\G;
*************************** 1. row ***************************
          THREAD_ID: 113
           EVENT_ID: 10
       END_EVENT_ID: 10
         EVENT_NAME: statement/sql/lock_tables
             SOURCE: socket_connection.cc:101
        TIMER_START: 18503556405463000
          TIMER_END: 18503556716572000
         TIMER_WAIT: 311109000
          LOCK_TIME: 293000000
           SQL_TEXT: lock table sbtest1 read  -- 这里可以看到,内部ID为113的线程对表sbtest1执行了加读锁语句
             DIGEST: 9f987e807ca36e706e33275283b5572b
        DIGEST_TEXT: LOCK TABLE `sbtest1` READ 
     CURRENT_SCHEMA: sbtest
......
1 row in set (0.00 sec)

本番環境の場合は、関連する開発者が特別な操作ならば、あなたはこのスレッドを殺すためにしようとすることができ、ことを確認した見つけることができます。

どのようにプロセスIDを内部ID 113の対応を知るためには、どのくらいでしょうか?あなたはperformance_schema.threadsテーブルで問い合わせることができます。113は、プロセスIDでないことに注意してくださいは、フリーズキルを行います。

select processlist_id from performance_schema.threads where thread_id=113;
+----------------+
| processlist_id |
+----------------+
| 18 |
+----------------+
1 row in set (0.00 sec)

kill 18;
Query OK, 0 rows affected (0.00 sec)

show processlist;
+----+-------+---------------------+--------+-------------+-------+---------------------------------------------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-------+---------------------+--------+-------------+-------+---------------------------------------------------------------+------------------+
| 3 | qfsys | 192.168.2.168:41042 | NULL | Binlog Dump | 18994 | Master has sent all binlog to slave; waiting for more updates | NULL |
| 19 | root | localhost | sbtest | Sleep | 480 | | NULL |
| 20 | root | localhost | NULL | Query | 0 | starting | show processlist |
+----+-------+---------------------+--------+-------------+-------+---------------------------------------------------------------+------------------+
3 rows in set (0.00 sec)

-- 返回执行update语句的会话2,语句已经执行成功
update sbtest1 set pad='xxx' where id=1;
Query OK, 0 rows affected (7 min 50.23 sec)
Rows matched: 0 Changed: 0 Warnings: 0

 

第四に、行レベルロックを保持している人を見つけます

MySQLの8.0ケースに関与performance_schema.data_lockテーブルが新規である、8.0より前のバージョンでは、唯一のMySQL performance_schema 5.7の学習の延長として、ここではサポートされていません。

あなたが適切なトランザクション情報にinformation_schema.innodb_trx、performance_schema.events_transactions_currentおよび他のテーブルからクエリを実行することができますが、彼らは、このトランザクションがロックを保持しているかわからないが、トランザクションは、コミットされていない時間である場合。information_schema.innodb_locksテーブルは、トランザクションのロック情報を記録するために使用されますが、ロック情報のニーズがトランザクションで発生するための表では、ロック待ちを記録しますが。

最初から8.0は、すべてのトランザクションをdata_locksに情報を記録する(とinformation_schema.innodb_locksテーブルを破棄)するロックperformance_schemaテーブルであって、関係があり、このテーブルは、唯一のストレージエンジンInnoDBの層を記録していることのノート(ロックを待機する必要はありません。ロック)。

 

まず、我々は、明示的にトランザクションを開いて、8.0でセッション(セッション1)を開きます

select * from t_luoxiaobo limit 1;
+----+------+---------------------+
| id | test | datet_time          |
+----+------+---------------------+
|  2 | 1    | 2017-09-06 01:11:59 |
+----+------+---------------------+
1 row in set (0.00 sec)

begin;
Query OK, 0 rows affected (0.00 sec)

update t_luoxiaobo set datet_time=now() where id=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

別のセッション(セッション2)クエリdata_locksテーブルを開き

select * from data_locks\G;
*************************** 1. row ***************************
          ENGINE: INNODB
  ENGINE_LOCK_ID: 55562:62
ENGINE_TRANSACTION_ID: 55562
        THREAD_ID: 54  # 持有线程内部ID
        EVENT_ID: 85
    OBJECT_SCHEMA: xiaoboluo # 库名
      OBJECT_NAME: t_luoxiaobo  # 表名
  PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
      INDEX_NAME: NULL  # 索引名称
OBJECT_INSTANCE_BEGIN: 140439793477144
        LOCK_TYPE: TABLE  # 表级锁
        LOCK_MODE: IX  # IX锁
      LOCK_STATUS: GRANTED  # 被授予状态
        LOCK_DATA: NULL

*************************** 2. row ***************************
          ENGINE: INNODB
  ENGINE_LOCK_ID: 55562:2:4:2
ENGINE_TRANSACTION_ID: 55562
        THREAD_ID: 54  # 持有锁线程内部ID
        EVENT_ID: 85
    OBJECT_SCHEMA: xiaoboluo  # 库名
      OBJECT_NAME: t_luoxiaobo #表名
  PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
      INDEX_NAME: PRIMARY  # 索引为主键
OBJECT_INSTANCE_BEGIN: 140439793474104
        LOCK_TYPE: RECORD  # 行锁
        LOCK_MODE: X  # 排它锁
      LOCK_STATUS: GRANTED  # 被授予状态
        LOCK_DATA: 2  # 被锁定的数据记录,这里的记录对应的是 INDEX_NAME: PRIMARY 的value
2 rows in set (0.00 sec)

最初の行のロックの2行がテーブルの上にt_luoxiaobo IXロックが存在している、その結果から見ることができ、Xの主キーインデックスを使用して、第2行はレコードロックをロックし、状態が付与され 

今、私たちは、2つのシナリオは、DMLロック待ちを発生するシミュレート。3行う同じ操作t_luoxiaoboは、コミットされていないトランザクションセッションの場合には、新たなセッション(セッション3)を開く、セッションテーブル

begin;
Query OK, 0 rows affected (0.00 sec)

update t_luoxiaobo set datet_time=now() where id=2;  -- 被阻塞

セッション2の照会のdata_locksテーブルに戻る、4行ロックレコードを見つけました

select * from performance_schema.data_locks\G;
*************************** 1. row ***************************
......
        THREAD_ID: 55
......
        LOCK_TYPE: TABLE
        LOCK_MODE: IX
      LOCK_STATUS: GRANTED
        LOCK_DATA: NULL
*************************** 2. row ***************************
          ENGINE: INNODB
  ENGINE_LOCK_ID: 55563:2:4:2
ENGINE_TRANSACTION_ID: 55563
        THREAD_ID: 55  # 内部线程ID
        EVENT_ID: 8
    OBJECT_SCHEMA: xiaoboluo
      OBJECT_NAME: t_luoxiaobo
  PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
      INDEX_NAME: PRIMARY  # 发生锁的索引名称
OBJECT_INSTANCE_BEGIN: 140439793480168
        LOCK_TYPE: RECORD  # 记录锁
        LOCK_MODE: X  # 排它锁
      LOCK_STATUS: WAITING  # 正在等待锁被授予
        LOCK_DATA: 2 # 锁定的索引value,这里与内部ID为54线程持有的主键值为2的X锁完全一样,说明这里就是被内部ID为54线程阻塞了
*************************** 3. row ***************************
......
        THREAD_ID: 54
.......
        LOCK_TYPE: TABLE
        LOCK_MODE: IX
      LOCK_STATUS: GRANTED
        LOCK_DATA: NULL
*************************** 4. row ***************************
......
        THREAD_ID: 54
        EVENT_ID: 85
    OBJECT_SCHEMA: xiaoboluo
      OBJECT_NAME: t_luoxiaobo
  PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
      INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 140439793474104
        LOCK_TYPE: RECORD
        LOCK_MODE: X
      LOCK_STATUS: GRANTED
        LOCK_DATA: 2
4 rows in set (0.00 sec)

ここでは直感的であるとの関係を見るためにロックを待つことができない、我々はsys.innodb_lock_waitsを見るためにビューを使用することができます

root@localhost : (none) 09:44:52> select * from sys.innodb_lock_waits\G;
*************************** 1. row ***************************
            wait_started: 2018-01-14 21:51:59
                wait_age: 00:00:11 <-- 等待时间
          wait_age_secs: 11
            locked_table: `xiaoboluo`.`t_luoxiaobo` <-- 表信息
    locked_table_schema: xiaoboluo
      locked_table_name: t_luoxiaobo
  locked_table_partition: NULL
locked_table_subpartition: NULL
            locked_index: PRIMARY <-- 主键字段
            locked_type: RECORD <-- 行锁
          waiting_trx_id: 55566
    waiting_trx_started: 2018-01-14 21:51:59
        waiting_trx_age: 00:00:11
waiting_trx_rows_locked: 1
waiting_trx_rows_modified: 0
            waiting_pid: 8 <-- 被阻塞的线程id
          waiting_query: update t_luoxiaobo set datet_time=now() where id=2  <-- 被阻塞者正执行的sql语句
        waiting_lock_id: 55566:2:4:2
      waiting_lock_mode: X <-- 锁模式
        blocking_trx_id: 55562
            blocking_pid: 7  <-- 阻塞的线程id
          blocking_query: NULL <-- 阻塞者正执行的sql语句(已经执行完了,但没提交)
        blocking_lock_id: 55562:2:4:2
      blocking_lock_mode: X
    blocking_trx_started: 2018-01-14 21:34:44
        blocking_trx_age: 00:17:26 <-- 持锁时间
blocking_trx_rows_locked: 1
blocking_trx_rows_modified: 1
sql_kill_blocking_query: KILL QUERY 7
sql_kill_blocking_connection: KILL 7  <-- kill阻塞者的语句
1 row in set (0.02 sec)

MySQLの5.7バージョンを使用してもsys.innodb_lock_waitsは、クエリの表示が、8.0で、別のテーブルを表示することができinformation_schema.innodb_locksとinformation_schema.innodb_lock_waitsテーブルが注文performance_schema.data_locksとperformance_schema.data_lock_waits表に以前のバージョンを置き換えるために使用(クエリに参加)。

5.6および以前のバージョンでは、SYSデフォルトのライブラリではありません、あなたの代わりに次のステートメントを使用することができます。

SELECT r.trx_wait_started AS wait_started,
  TIMEDIFF(NOW(), r.trx_wait_started) AS wait_age,
  TIMESTAMPDIFF(SECOND, r.trx_wait_started, NOW()) AS wait_age_secs,
  rl.lock_table AS locked_table,
  rl.lock_index AS locked_index,
  rl.lock_type AS locked_type,
  r.trx_id AS waiting_trx_id,
  r.trx_started as waiting_trx_started,
  TIMEDIFF(NOW(), r.trx_started) AS waiting_trx_age,
  r.trx_rows_locked AS waiting_trx_rows_locked,
  r.trx_rows_modified AS waiting_trx_rows_modified,
  r.trx_mysql_thread_id AS waiting_pid,
  sys.format_statement(r.trx_query) AS waiting_query,
  rl.lock_id AS waiting_lock_id,
  rl.lock_mode AS waiting_lock_mode,
  b.trx_id AS blocking_trx_id,
  b.trx_mysql_thread_id AS blocking_pid,
  sys.format_statement(b.trx_query) AS blocking_query,
  bl.lock_id AS blocking_lock_id,
  bl.lock_mode AS blocking_lock_mode,
  b.trx_started AS blocking_trx_started,
  TIMEDIFF(NOW(), b.trx_started) AS blocking_trx_age,
  b.trx_rows_locked AS blocking_trx_rows_locked,
  b.trx_rows_modified AS blocking_trx_rows_modified,
  CONCAT('KILL QUERY ', b.trx_mysql_thread_id) AS sql_kill_blocking_query,
  CONCAT('KILL ', b.trx_mysql_thread_id) AS sql_kill_blocking_connection
FROM information_schema.innodb_lock_waits w
  INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
  INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id
  INNER JOIN information_schema.innodb_locks bl ON bl.lock_id = w.blocking_lock_id
  INNER JOIN information_schema.innodb_locks rl ON rl.lock_id = w.requested_lock_id
ORDER BY r.trx_wait_started;

参考:「MySQLのパフォーマンスチューニングのピラミッド法則」

公開された295元の記事 ウォン称賛35 ビュー80000 +

おすすめ

転載: blog.csdn.net/Hehuyi_In/article/details/99351846