インタビュアー: MySQL の自動インクリメント主キーは連続していなければなりませんか? ほとんどの人が勘違いしてしまうでしょう!

テスト環境:

MySQL バージョン: 8.0

データベース テーブル: T (主キー ID、一意のインデックス c、共通フィールド d)

ビジネス設計が自動インクリメント キーの連続性に依存している場合、この設計は自動インクリメント キーが連続していることを前提としています。しかし実際には、自動インクリメント主キーは継続的なインクリメントを保証できないため、そのような仮定は間違っています。

オープンソースで無料の Spring Boot 実践プロジェクトを推奨します。

https://github.com/javastacks/spring-boot-best-practice

1. 自己インクリメントの属性特性:

1. 自動インクリメント主キー値はどこに保存されますか?

MySQL5.7バージョン

MySQL 5.7 以前では、自動インクリメント値はメモリに保存され、永続化されませんでした。各再起動後、初めてテーブルを開いたときに、自己インクリメント値の最大値が検出されmax(id)max(id)+1それがテーブルの現在の自己インクリメント値として。

MySQL8.0以降のバージョン

MySQL バージョン 8.0 では、自己増分変更はredo logに、redo log再起動前の値に基づいて復元されます。

テーブルの詳細を確認することで現在の自己インクリメント値を確認したり、テーブル パラメータの詳細な値AUTO_INCREMENT(AUTO_INCREMENTつまり、現在のデータ テーブルの自己インクリメント値) を確認したりできます。

2. 自動インクリメント主キー値の変更メカニズムは何ですか?

テーブル t では、主キー ID を自己インクリメント値として定義しましたが、データ行を挿入するときの自己インクリメント値の動作は次のようになります。

  1. データの挿入時に id フィールドが 0、null、または未指定の値として指定された場合は、このテーブルの現在のAUTO_INCREMENT値を。
  2. データの挿入時に id フィールドに特定の値が指定されている場合は、ステートメントで指定された値を直接使用します。

挿入する値と現在の自動インクリメント値の大小関係に応じて、自動インクリメント値の変更結果も異なります。挿入される値が X で、現在の自動インクリメント値が Y であると仮定します。

  1. X<Y の場合、このテーブルの自己インクリメント値は変更されません。
  2. X≧Yの場合は、現在の自己インクリメント値を新しい自己インクリメント値に変更する必要があります。

2. 新しいステートメントの自己インクリメント主キーはどのように変化しますか。

次の SQL ステートメントを実行して、自動インクリメント主キーがどのように変化するかを観察します。

insert into t values(null, 1, 1);

フローチャートを以下に示します

プロセス手順:

  • AUTO_INCREMENT=1 (次回データ挿入時に自己インクリメント値を自動生成する必要がある場合、id=1 が生成されることを示します。)
  • insert into t names(null, 1, 1) (実行プログラムは InnoDB エンジン インターフェイスを呼び出して行を書き込み、渡された行の値は (0,1,1) です)
  • get AUTO_INCREMENT=1 (InnoDB は、ユーザーが自動インクリメント ID の値を指定していないことを検出し、テーブル t の現在の自動インクリメント値 1 を取得します)
  • AUTO_INCREMENT=2 t 値 (1, 1, 1) に挿入(受信行の値を (1,1,1) に変更し、自己インクリメント値を 2 に変更します)
  • insert (1, 1, 1) は挿入操作を実行し、プロセスは終了します

このプロセスでは、自己インクリメント +1 が最初に実行され、次に新しいステートメントが実行されることがわかります。この操作ではアトミック操作が実行されないことがわかりますが、SQL ステートメントの実行が失敗した場合でも、自己インクリメントは連続的に行われますか?

3. 不連続な自動インクリメント主キー値:(一意の主キーの競合)

以下のSQL文を実行すると

insert into t values(null, 1, 1);

自己インクリメントの変更メカニズムに従って、初めて正常に追加できます。データの挿入時に id フィールドが 0、null、または未指定の値として指定された場合は、このテーブルの現在のAUTO_INCREMENT値を。

次の SQL 文を 2 回目に実行すると、エラーが発生します。テーブルの c フィールドは一意のインデックスであるため、Duplicate key errorエラーが発生し、新しい追加は失敗します。

例えば:

  • AUTO_INCREMENT=2 (次回データ挿入時に自己インクリメント値を自動生成する必要がある場合、id=2 が生成されることを示します。)
  • insert into t names(null, 1, 1) (実行プログラムは InnoDB エンジン インターフェイスを呼び出して行を書き込み、渡された行の値は (0,1,1) です)
  • get AUTO_INCREMENT=2 (InnoDB は、ユーザーが自動インクリメント ID の値を指定していないことを検出し、テーブル t の現在の自動インクリメント値 2 を取得します)
  • AUTO_INCREMENT=3 t 値 (2, 1, 1) に挿入(受信行の値を (2,1,1) に変更し、自己インクリメント値を 3 に変更します)
  • insert (2, 1, 1) は挿入操作を実行します。 c=1 のレコードがすでに存在するためDuplicate key error、 report ステートメントが返されます。

実際のデータ挿入操作が実行される前に、このテーブルの自己インクリメント値が 3 に変更されることがわかります。このステートメントが実際に実行されると、一意キー c との競合のため、行 id=2 は正常に挿入されませんが、自己インクリメント値も元に戻されません。したがって、その後、新しいデータ行を挿入するときに取得される自動インクリメント ID は 3 になります。つまり、自動インクリメント主キーが不連続になる場合があります。

4. 自己インクリメントする主キー値の不連続: (トランザクションのロールバック)

実際、トランザクションのロールバックの原理は上記と同じで、すべて新規追加の失敗につながる例外によるものですが、自己増分値はロールバックされていません。

5. 自己インクリメントする主キー値の不連続性:(バッチ挿入)

データをバッチ挿入するステートメントの場合、MySQL にはバッチ アプリケーションの ID を自動インクリメントする戦略があります。

  1. ステートメントの実行中、自動インクリメント ID の最初のアプリケーションは 1 を割り当てます。
  2. 1 が使い果たされた後、このステートメントは 2 番目の自己インクリメント ID に適用され、2 が割り当てられます。
  3. 2 つが使い果たされた後も、ステートメントは同じであり、自動インクリメント ID の 3 番目のアプリケーションでは 4 が割り当てられます。
  4. 同様に、同じステートメントが自動インクリメント ID にも適用され、毎回適用される自己インクリメント ID の数は前回の 2 倍になります。

以下のSQL文を実行します(最初にテーブルtにデータを4つ追加し、テーブルtt作成後にテーブルtのデータを一括追加)

insert into t values(null, 1,1);
insert into t values(null, 2,2);
insert into t values(null, 3,3);
insert into t values(null, 4,4);
create table tt like t;
insert into tt(c,d) select c,d from t;

insert into tt values(null, 5,5);

最初のアプリケーションでは id=1 が割り当てられ、2 回目では id=2 と id=3 が割り当てられ、3 回目では id=4 から id=7 が割り当てられました。再度実行するとinsert into t2 values(null, 5,5)、実際に挿入されるデータは(8,5,5)となり、自動インクリメントの主キーが不連続になります。

6. 自己インクリメントする主キー値の最適化

1. 自己増加ロックとは

自己増加ロックは、特別なテーブルレベルのロックです。そして、トランザクションがAUTO_INCREMENT列を含むテーブルにデータを追加すると、自己増加ロックが保持されます。トランザクション A がこの操作を実行している場合、別のトランザクション B が INSERT ステートメントを実行しようとすると、トランザクション A が実行されるまでトランザクション B はブロックされます。自己増加ロックを解除します。

2. 自己増加ロックの最適化とは何ですか?

MySQL バージョン 5.0 では、自己増加ロックの範囲はステートメント レベルです。つまり、ステートメントがテーブルの自己増加ロックに適用される場合、ロックはステートメントが実行されるまで解放されません。明らかに、そのような設計は同時実行の程度に影響します。MySQL 5.1.22 バージョンでは新しい戦略が導入され、新しいパラメータが追加されましたinnodb_autoinc_lock_mode。デフォルト値は 1 です。

従来モード(トラディショナル)

このパラメータの値が 0 に設定されている場合、以前の MySQL 5.0 バージョンの戦略が採用されることを意味します。つまり、ステートメントの実行が完了した後にロックが解放されます。

従来のモードではデータの一貫性を保証できますが、INSERT 操作を同時に実行する複数のトランザクションがある場合、AUTO-INC同時に実行できる INSERT ステートメントは 1 つだけであるため、MySQL の存在により MySQL のパフォーマンスがわずかに低下します。

間欠モード(連続)

このパラメータの値が 1 に設定されている場合: 通常の挿入ステートメントの場合、自己増加ロックはアプリケーションの直後に解放されます。insert … selectこのステートメントは終了します。

不連続モードはデータの整合性を保証できますが、複数のトランザクションで同時にINSERTバッチ操作を実行した場合、ロック待ち状態となります。私たちのビジネスで大量のデータが挿入されると、その時点で MySQL のパフォーマンスが大幅に低下します。

インターリーブモード (インターリーブ)

このパラメータの値が 2 に設定されている場合、自動インクリメント主キーを適用するすべてのアクションは、適用後にロックを解放することになります。

分散モードでは、ロック設定は実行しませんでした。特定の状況下では、MySQL のパフォーマンスは保証されますが、データの一貫性は保証できません。分散モードでマスター/スレーブ レプリケーションを実行する場合、バイナリ ログ形式が行形式でない場合、マスター/スレーブ レプリケーションは不整合になります。

7. MySQL8.0 で行われた最適化

innodb_autoinc_lock_mode=2MySQL8.0 以降のバージョンでは、デフォルトでに設定されていますbinlog_format=row.これは、バッチでデータを挿入するときにデータの一貫性の問題を発生させることなく同時実行性を向上させるためinsert … selectに。

著作権に関する声明: この記事は、CSDN ブロガー「You owe」によるオリジナルの記事です。CC 4.0 BY-SA 著作権契約に従い、転載する場合は、元のソース リンクとこの声明を添付してください。元のリンク: https://blog.csdn.net/qq_48157004/article/details/128356734

最近のおすすめ記事:

1. 1,000 を超える Java 面接の質問と回答 (2022 年最新バージョン)

2.素晴らしい!Java コルーチンが登場します。

3. Spring Boot 2.x チュートリアル、包括的すぎる!

4.画面を爆発や爆発で埋め尽くさないで、デコレーターモードを試してください。これがエレガントな方法です。

5.最新リリースの「Java 開発マニュアル (松山編)」をすぐにダウンロードしてください!

気分がいいので、「いいね!」+「転送」を忘れないでください!

おすすめ

転載: blog.csdn.net/youanyyou/article/details/130931052