序文:この記事を通して、MySQL 5.7.18のユーザーがパーティションテーブルの使用における落とし穴に気づき、このバージョンを踏み続けることを回避できることを願っています。同時に、ソースコードを共有することにより、MySQL 5.7.18をアップグレードするときのパーティションテーブルのパフォーマンス低下の根本原因は、MySQLソースコード愛好家がパーティションテーブル実装でのロックの使用を示すことです。
問題の説明
MySQL 5.7では、パフォーマンスに関連する多くの改善があります。一時テーブルに関連するパフォーマンスの改善、接続確立速度の最適化、レプリケーションと分散に関連するパフォーマンスの改善などが含まれます。基本的に、構成を変更する必要はありません。バージョン5.7にアップグレードするだけで、パフォーマンスが大幅に向上します。
環境をテストし、データベースをバージョン5.7.18にアップグレードし、MySQLバージョン5.7.18が私たちの期待を満たしているかどうかを確認しています。監視は一定期間実行されており、開発フィードバックがあり、データベースのパフォーマンスは以前のバージョン5.6.21のパフォーマンスよりも低くなっています。主なパフォーマンス機能は、より多くのロックタイムアウト状況に遭遇することです。パフォーマンスの低下に関連するテーブルがすべてパーティションテーブルであるという開発からの別のフィードバック。更新はすべて主キーです。このフィードバックは私たちの注意を引いた。私たちは次のように試みました:
- データベースのバージョンは5.7.18です。パーティションテーブルを予約すると、パフォーマンスが低下します。
- データベースのバージョンは5.7.18で、テーブルは非パーティションテーブルに調整されており、パフォーマンスは正常です。
- データベースのバージョンをバージョン5.6.21にロールバックし、パーティションテーブルを保持します。パフォーマンスは正常です
上記のテストを通じて、このパフォーマンスの低下はMySQL5.7バージョンのアップグレードに関連しているとおおまかに判断しました。
問題を再現する
テスト環境のデータベーステーブル構造はより複雑であり、呼び出し関係もより複雑です。問題をさらに分析して特定するために、繭を取り、次の簡単な繁殖プロセスを構築しました
// 创建一个测试分区表t2:
CREATE TABLE `t2`(
`id` INT(11) NOT NULL,
`dt` DATETIME NOT NULL,
`data` VARCHAR(10) DEFAULT NULL,
PRIMARYKEY (`id`,`dt`),
KEY`idx_dt`(`dt`)
) ENGINE=INNODB DEFAULTCHARSET=latin1
/*!50100 PARTITION BY RANGE (to_days(dt))
(PARTITION p20170218 VALUES LESS THAN (736744)ENGINE = InnoDB,
PARTITIONp20170219 VALUES LESS THAN (736745) ENGINE = InnoDB,
PARTITIONpMax VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
// 插入测试数据
INSERT INTO t2 VALUES (1, NOW(), '1');
INSERT INTO t2 VALUES (2, NOW(), '2');
INSERT INTO t2 VALUES (3, NOW(), '3');
// SESSION 1 对id = 1的 记录 做一个更新操作,事务先不提交。
BEGIN;UPDATE t2 SET DATA = '12' WHERE id = 1;
// SESSION 2 对id = 2 的记录做一个更新。
BEGIN;UPDATE t2 SET DATA = '21' WHERE id = 2;
セッション2で、この更新操作が待機していることがわかりました。IDは主キーです。論理的には、主キーID = 1のレコードの更新は、主キーID = 2のレコードの更新に影響しません。
information_schemaの下のinnodb_locksテーブルをクエリします。このテーブルは、InnoDBトランザクションが適用しようとしているがまだ取得していないロックと、他のトランザクションをブロックするトランザクションが所有するロックを記録するために使用されます。2つのレコードがあります。
この時点でinnodb_locksテーブルを確認します。トランザクションid = 40021はページ3の2行目のレコードをロックし、トランザクションid = 40022を続行できなくなります。
データベースをバージョン5.6.21にロールバックすると、上記のシナリオを再現できなくなります。
さらなる分析
innodb_locksテーブルによって提供される情報によると、問題はInnoDBが不適切な行をロックしたことです。このテーブルは、メモリストレージエンジンです。メモリストレージエンジンの挿入インターフェイスにブレークポイントを設定し、次のスタック情報を取得します。赤いボックスの部分を特定し、ロック情報をinnodb_locksテーブルに書き込みます。
また、関数fill_innodb_locks_from_cacheで、データが行に書き込まれるたびに、次のコードでCacheオブジェクトから取得されることが確認されています。
トランザクションロック情報はキャッシュに格納されることがわかっているため、キャッシュ内のデータがどのように追加されるかをさらに調べる必要があります。キャッシュオブジェクトがinnodbコードのどこにあるかを検索して、関数add_lock_to_cacheを見つけます。この関数にデバッグ用のブレークポイントを設定した後、その内容がinnodb_locksテーブルに入力されたデータと一致していることがわかります。この関数で使用されるロックオブジェクトを特定します。これは、探しているロックオブジェクトです。
lock_tタイプが使用されている場所をトラブルシューティングします。スクリーニングとデバッグの後、RecLock :: lock_add関数で、生成された行ロックが、ロックが配置されているトランザクションリンクリストに追加されていることがわかります。
RecLock :: lock_add関数は、行ロック生成の理由を推測できます。したがって、関数にブレークポイントを設定して、関数スタックを表示し、次のスタックの赤いボックスの位置に関数を配置します。
次のPartition_helper :: handle_ordered_index_scanのコードが追跡されます。このコードの分析によると、m_part_spec.end_partはロックされる行の最大数を決定します。これが異常な行ロック生成の理由です。
結局、問題はm_part_spec.end_partの生成に帰着します。end_partの使用を調査することにより、使用前の変数の初期設定値が最終的にget_partition_set関数に配置されます。コードから、単一のレコードが更新されるたびに、インデックススキャンがロックされると、パーティションテーブル内の同じ数の行がロックされることがわかります。これが根本的な原因です。
検証の結論
以前の分析によると、単一のレコードの各更新操作は、パーティションテーブル内の同じ数の行をロックします。調査結果の検証を試みます。
次の2つのレコードを追加します。
INSERT INTO t2 VALUES (4, NOW(), '4');
INSERT INTO t2 VALUES (5, NOW(), '5');
// SESSION 1 对id = 1的 记录 做一个更新操作,事务先不提交。
BEGIN;UPDATE t2 SET DATA = '12' WHERE id = 1;
// SESSION 2 现在对id = 4 的记录做一个更新。
BEGIN;UPDATE t2 SET DATA = '44' WHERE id = 4;
id = 4への更新は正常に続行できることがわかりました。id = 1の更新の影響を受けません。これは、id = 4のレコードがテストケースのパーティション数を超えており、ロックされないためです。実際のアプリケーションでは、パーティションテーブルで定義されたパーティションの数は、テストケースでは3つではなく、数十または数百になります。このようなロックの結果、更新状況でのロック競合が悪化し、トランザクションがロック待機状態になります。次の図に示すように、各トランザクションにはN個の行ロックがあるため、これらのロックされたレコードが互いにカバーし合う可能性が大幅に向上し、並行性の低下と効率の低下につながります。
結論として
上記の分析により、これはMySQL 5.7のリグレッションであると確信しています。オープンソースコミュニティにバグを提出しました。オラクルはそれが問題であることを確認しており、このバグはさらに分析および調査する必要があります。
注意を払い、迷子にならないでください
さてさて皆さん、以上がこの記事の全内容であり、こちらをご覧いただける方はみなタレントです。前述したように、PHPには多くの技術的なポイントがあります。多すぎるため、書くことは本当に不可能であり、書いた後はあまり読まないので、必要に応じて、PDFとドキュメントに整理します。できる
クリックして秘密のコードを入力してください:PHP +「プラットフォーム」
より多くの学習コンテンツについては、給与が段階的に上がることを確認するために読むことができる限り、[Comparative Standard Factory] Catalog of Excellent PHP Architectチュートリアルのカタログにアクセスできます(継続的な更新)。
上記のコンテンツはあなたを助けることを望んでいます。多くのPHPワーカーは、高度になると常にいくつかの問題やボトルネックに遭遇します。ビジネスコードを書きすぎても、方向性はありません。どこから改善を始めればよいかわかりません。これを含むいくつかの情報をまとめました。ただし、これらに限定されません:分散アーキテクチャ、高スケーラビリティ、高パフォーマンス、高同時実行性、サーバーパフォーマンスチューニング、TP6、laravel、YII2、Redis、Swoole、Swoft、Kafka、Mysql最適化、シェルスクリプト、Docker、マイクロサービス、Nginxなど。複数の知識ポイント、高度で先進的なドライグッズは無料で誰とでも共有でき、必要なものは私のPHPテクノロジー交換グループに参加できます