トランザクションの深い理解とロック機構(下)

MySQLのロックカテゴリ

 

ページレベルのロック、テーブルレベルのロック、行レベルロック:以前にロックを述べ、次のように詳細にMySQLのロックを説明します、我々は分類のロックを見てみましょう、MySQLではロックの3つのレベルがあります。

  • テーブルレベルロック:小さなオーバーヘッド、高速ロック、デッドロックしない、ロック大きいサイズ、並行性の最高と最低度のロック競合の確率。その上のMyISAM、メモリ、InnoDBは、BDBストレージエンジンと:それは起こります。

  • 行レベルのロッキング:大きなオーバヘッド、低速ロックは、ロック粒度ロック競合の最小及び最小確率、並行性の最高度、デッドロックが存在することになります。それは起こります:InnoDBストレージエンジンを。

  • ページレベルのロッキング:オーバーヘッドロックとテーブルと行ロックの間の時間境界は、一般に粒度テーブルと行ロックの境界、同時実行をロック、デッドロックが存在することになります。それは起こります:BDBストレージエンジンを。

図に示すように、3つのレベルは、それぞれのストレージエンジンロック関係に対応します。

 

 

注:MySQLのテーブルロックの読み取りと書き込みロックが含まれます。ただ、この表のロックモードは、互換性の行列ができている覚えています。

InnoDBのをロック

MySQLのInnoDBストレージエンジンでは、行およびテーブルロックにロックします。前記ロックは、二つのロック列を含みます。

  • 共有ロック(S):トランザクションが排他ロックを設定し、同じデータを取得するために他のトランザクションを防ぐために、行を読み取ることができます。

  • 排他ロック(X):彼は排他的ロックトランザクションの更新データを取得できるようにするため、他のトランザクションを阻止するには、同じデータセットを共有するために作られたロックと排他的な書き込みロックをお読みください。

さらに、行およびテーブルのロック、マルチ粒度ロック機構の共存を可能にするために、InnoDBは意図的ロック(意図ロックの)内部使用の二種類が、両方の意図ロック表ロックがあります。表ロックは3つに分割されています。

  • 意図共有ロックは、(IS):トランザクションの計画はロックがテーブルの上にロックIS取得する必要があります共有データラインにトランザクションの前にロックを共有データ行の行を追加します。

  • 意図排他ロック(IX):権利は、データライン行排他ロックに追加していき、トランザクションがデータ行の行を追加して、テーブルの上に彼のロックIXロック前に取得する必要があります。

  • カウンタサブ成長によって最大カウント値を得るためにカウンタが増加するので特別なテーブルロック:ロックインクリメント(AUTO-INCロック)「ロック」。

私たちは、行ロックを追加する前に、テーブルレベルの意図ロックを取得しなければならない、またはタイムアウトinnodb_lock_wait_timeout待ち時間は、ロールバックにトランザクションがinnodb_rollback_on_timeoutによるかどうかを決定します。

InnoDBの増加セルフロック

MySQLのInnoDBストレージエンジンでは、我々はテーブル構造を設計し、私は通常、主キーとして増分を追加することをお勧めします。ここでは、それは特別なロックを伴います:ロック増分(すなわち:AUTO-INCロック)テーブルロックに属し、INSERTの直後にリリースされます。私たちは、増分ロックステータス情報を表示するには、showエンジンInnoDBのステータス\ Gを実行することができます。

 

当然のセルフロックの増加、コアパラメータがあり、そのinnodb_autoinc_lock_modeに焦点を当てる必要性は、三つの値0,1,2を有します。ライン上のデフォルトを保管してください。以下のように公式文書を参照することができ、特定の意味は、それが、ここでは繰り返しません。

 

 下に示すような関係行列をロックInnoDBは、:+互換性を示しているが、 - 互換性がない示します。

 

 

InnoDBの行ロック

 

InnoDBの行ロックは、ロックを達成するために、データ・ページ(レコード)にインデックスを記録することによって得られます。レコードのロック、ギャップロックとネクストキーロック:三つの主要なアルゴリズムがあります。

  • レコードのロックはロック:個々の行のロック(ロックデータは、ギャップをロックされていません)。

  • ギャップロックロック:ギャップロック、ロックの範囲、(GAPデータをロックしない、唯一フロントラッチデータ)そのものを記録除きます。

  • ネクストキーロックロック:以前のデータとロックギャップ、同時にデータをロックします。

InnoDBのロック問題のトラブルシューティング

InnoDBのロック問題のトラブルシューティングには、通常、二つの方法があります。

  • innodb_lock_monitorテーブルを開いた後、それ以外の場合は、パフォーマンスに影響を与えるだろう、クローズドの使用に注意を払うことを忘れないでください。

  • MySQLの5.5バージョンの後、あなたはinnodb_locks、innodb_lock_waits、innodb_trxロック問題のトラブルシューティングのInnoDBの三面以下のライブラリINFORMATION_SCHEMAを表示することができます。

InnoDBのロック動作

InnoDBはインデックスの異なるロック動作の分析は、以下のいくつかの例を与えます。ロック分離レベルの分析、我々のRRとリンクする必要があるが、例えば、4つのシーンを分析することです。

  • プライマリ+のRR。

  • 唯一のキー+ RR。

  • 非一意キー+ RR。

  • いいえ、インデックス+のRRません。

以下に示すように、主キー+ RR:以下は最初のケースを説明します。

 

 

仮定は以下のとおりです。

  • update t1 set name=‘XX’ where id=10。

  • id 为主键索引。

加锁行为:仅在 id=10 的主键索引记录上加 X锁。

 

第二种情况:唯一键 + RR,如下图所示。

 

 

假设条件是:

  • update t1 set name=‘XX’ where id=10。

  • id 为唯一索引。

加锁行为:

  • 先在唯一索引 id 上加 id=10 的 X 锁。

  • 再在 id=10 的主键索引记录上加 X 锁,若 id=10 记录不存在,那么加间隙锁。

第三种情况:非唯一键 + RR,如下图所示。

 

 

假设条件是:

  • update t1 set name=‘XX’ where id=10。

  • id 为非唯一索引。

加锁行为:

  • 先通过 id=10 在 key(id) 上定位到第一个满足的记录,对该记录加 X 锁,而且要在 (6,c)~(10,b) 之间加上 Gap lock,为了防止幻读。然后在主键索引 name 上加对应记录的X 锁;

  • 再通过 id=10 在 key(id) 上定位到第二个满足的记录,对该记录加 X 锁,而且要在(10,b)~(10,d)之间加上 Gap lock,为了防止幻读。然后在主键索引 name 上加对应记录的X 锁;

  • 最后直到 id=11 发现没有满足的记录了,此时不需要加 X 锁,但要再加一个 Gap lock: (10,d)~(11,f)。

第四种情况:无索引 + RR,如下图所示。

 

 

假设条件是:

  • update t1 set name=‘XX’ where id=10。

  • id 列无索引。

加锁行为:

  • 表里所有行和间隙均加 X 锁。

至此,我们分析了四种索引在 RR 隔离级别下的加锁行为,那么在 RC 隔离级别下的加锁行为又是怎样的呢?这个问题留给你自己去思考,答案将在下一节课中给出。

 

在前文中,我们有提到分析锁问题的三个视图,在实际的使用中,可以在数据库发生阻塞的时候,将这三个视图做联合查询来帮助获取详细的锁信息,帮助快速定位找出造成死锁的元凶和被害者,以及具体的事务。

InnoDB 死锁

在 MySQL 中死锁不会发生在 MyISAM 存储引擎中,但会发生在 InnoDB 存储引擎中,因为 InnoDB 是逐行加锁的,极容易产生死锁。那么死锁产生的四个条件是什么呢?

  • 互斥条件:一个资源每次只能被一个进程使用; 

  • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放; 

  • 不剥夺条件:进程已获得的资源,在没使用完之前,不能强行剥夺; 

  • 循环等待条件:多个进程之间形成的一种互相循环等待资源的关系。

在发生死锁时,InnoDB 存储引擎会自动检测,并且会自动回滚代价较小的事务来解决死锁问题。但很多时候一旦发生死锁,InnoDB 存储引擎的处理的效率是很低下的或者有时候根本解决不了问题,需要人为手动去解决。

 

既然死锁问题会导致严重的后果,那么在开发或者使用数据库的过程中,如何避免死锁的产生呢?这里给出一些建议:

  • 加锁顺序一致;

  • 尽量基于 primary 或 unique key 更新数据。

  • 单次操作数据量不宜过多,涉及表尽量少。

  • 减少表上索引,减少锁定资源。

  • 相关工具:pt-deadlock-logger。

资源争用

下面分享一个基于资源争用导致死锁的情况,如下图所示。

 

 

session1 首先拿到 id=1 的锁,session2 同期拿到了 id=5 的锁后,两者分别想拿到对方持有的锁,于是产生死锁。

元数据锁

下面分享一个 Metadata lock(即元数据锁)导致的死锁的情况,如下图所示。

 

 

session1 和 session2 都在抢占 id=1 和 id=6 的元数据的资源,产生死锁。

 

查看 MySQL 数据库中死锁的相关信息,可以执行 show engine innodb status\G 来进行查看,重点关注 “LATEST DETECTED DEADLOCK” 部分。

 

给大家一些开发建议来避免线上业务因死锁造成的不必要的影响。

  • 更新 SQL 的 where 条件时尽量用索引;

  • 加锁索引准确,缩小锁定范围;

  • 减少范围更新,尤其非主键/非唯一索引上的范围更新。

  • 控制事务大小,减少锁定数据量和锁定时间长度 (innodb_row_lock_time_avg)。

  • 加锁顺序一致,尽可能一次性锁定所有所需的数据行。

本课时到这里就全部结束了,今天主要讲了 MySQL 的事务及其特性、并发事务带来的问题、事务的隔离级别、多版本并发控制 MVCC、InnoDB 锁分类、InnoDB 锁算法、InnoDB 死锁及其优化建议。

おすすめ

転載: www.cnblogs.com/tesla-turing/p/12036568.html