MySQL自動インクリメントフィールドは自動的にリセットされます


12

INT(11)として設定された自動インクリメントフィールドを持つMySQLテーブルがあります。このテーブルには、アプリケーションで実行されているジョブのリストがほとんど格納されます。アプリケーションの存続期間中の任意の時点で、テーブルには何千ものエントリが含まれているか、完全に空(つまり、すべてが終了)になっている可能性があります。

フィールドは、他のものに対して外部キーではありません。

実際にリセットをトラップすることはできませんでしたが、自動インクリメントはランダムにゼロにリセットされるようです。

この問題は、自動インクリメントフィールドがたとえば600,000レコード程度に達し、しばらくしてから自動インクリメントフィールドが低い1000年代で実行されているように見えるために明らかになります。

テーブルが空の場合、自動インクリメントが自動的にリセットされるようです。

これは可能ですか、可能であれば、どのようにオフにするか、リセット方法を変更しますか?

そうでない場合、なぜこれを行うのかについての説明はありますか?

ありがとう!


MySQLのバージョンは何ですか?トランザクションまたはレプリケーションが使用されていますか?
thinice

回答:


26

自動インクリメントカウンタは、ディスクではなくメインメモリにのみ保存されます。

http://dev.mysql.com/doc/refman/4.1/en/innodb-auto-increment-handling.html

このため、サービス(またはサーバー)が再起動すると、次のことが起こります。

サーバーの起動後、テーブルtへの最初の挿入に対して、InnoDBは次のステートメントに相当するものを実行します。SELECT MAX(ai_col)FROM t FOR UPDATE;

InnoDBは、ステートメントによって取得された値を1増分し、それを列およびテーブルの自動増分カウンターに割り当てます。テーブルが空の場合、InnoDBは値1を使用します。

したがって、簡単な英語では、MySQLサービスの開始後、テーブルの自動インクリメント値がどうあるべきかがわかりません。したがって、最初に行を挿入すると、自動インクリメントを使用するフィールドの最大値が検出され、この値に1が加算されて、結果の値が使用されます。行がない場合は、1から始まります。

ユーザーがサードパーティの支払いサイトにリダイレクトされるマルチスレッド環境で、テーブルとmysqlの自動インクリメント機能を使用してIDをきちんと管理していたため、これは私たちにとって問題でした。そのため、サードパーティが取得して返送したIDが一意であり、そのままであるようにする必要がありました(もちろん、ユーザーがリダイレクト後にトランザクションをキャンセルする可能性があります)。

そこで、行を作成し、生成された自動インクリメント値を取得し、行を削除してテーブルをクリーンに保ち、値を支払いサイトに転送していました。InnoDBがAI値を処理する方法の問題を修正するために私たちがやったことは次のとおりでした。

$query = "INSERT INTO transactions_counter () VALUES ();";
mysql_query($query);
$transactionId = mysql_insert_id();
$previousId = $transactionId - 1;
$query = "DELETE FROM transactions_counter WHERE transactionId='$previousId';";
mysql_query($query); 

これにより、テーブルを不必要に爆破することなく、常にテーブル内の行として生成された最新のtransactionIdが保持されます。

これに遭遇する可能性のある他の誰にも役立つことを願っています。

編集(2018-04-18)

Finesseが以下で言及したように、この動作はMySQL 8.0以降で変更されているようです。

https://dev.mysql.com/worklog/task/?id=6204

そのワークログの文言はせいぜい不完全ですが、それらの新しいバージョンのInnoDBはリブート後も永続的なautoinc値をサポートするようになりました。

-グレミオ


最初の投稿としては悪くありません。+1。
ceejayoz

そこにグレミオのちょっとした知識。ありがとう!! 私はこれを完全に延期し、後日レビューするために問題を内部的にアーカイブしましたが、それに戻ってあなたのソリューションは魅力的です!
フーリガン

3

この問題が発生し、最適化テーブルが空のテーブルで実行されると、自動インクリメント値もリセットされることを発見しました。このMySQLバグレポートを参照してください。

回避策として、次のことができます。

ALTER TABLE a AUTO_INCREMENT=3 ENGINE=innoDB;

の代わりにOPTIMIZE TABLE

これはMySQLが内部的に行うことです(明らかにAuto increment値を設定せずに)


2

暗闇でのショット-アプリケーションがTRUNCATE TABLE処理を完了したときにテーブルを空にするためにa を使用している場合、自動インクリメントフィールドがリセットされます。ここに質問に関する簡単な議論があります。そのリンクはInnoDBが切り捨てでauto_incrementsをリセットしないと述べていますが、それはバグとして報告され、数年前に修正されました。

私の推測が正しいと仮定すると、問題を解決するために切り捨てから削除に変更できます。


TRUNCATEを使用しているとは思いませんでしたが、確認する必要がありました。念のため、PHPドライバーレベルまで検証することさえしました。しかし、そうではありませんでした。ただし、可能な解決策を高く評価してください。
フーリガン

1

その値の明示的なリセット、またはそのフィールドのドロップ/再作成、または他の同様の暴力的な操作のみがauto_incrementカウンターをリセットする必要があります。(TRUNCATEは本当に良い理論でした。)目撃した最後の値がわずか600kのとき、突然32ビットINTをラップすることは不可能のようです。テーブルが空になったからといってリセットすべきではありません。mysqlのバグか、PHPコードに何かがあります。または、隣のキュービクルの男があなたをだましている。

バイナリログをオンにしてデバッグできます。これには、次のようなステートメントが含まれているためです。

SET INSERT_ID=3747670/*!*/;

そうすれば、少なくとも、カウンターがリセットされる直前を含めて、そのテーブルで何が起こっているかの詳細をすべて見ることができます。


デバッグのヒントをありがとう。それは、私はserverfaultの中にチェックするために必要なので、しばらくして、私はあなたの先端に感謝しています
Hooligancat


0

InnoDBはディスクに自動インクリメント値を保存しないため、MySQLサーバーがシャットダウンされるとそれを忘れます。MySQLが再び起動されると、InnoDBエンジンは次の方法で自動インクリメント値を復元しますSELECT (MAX(id) + 1) AS auto_increment FROM table。これはMySQLバージョン8.0で修正さたバグです。

テーブルエンジンを変更して問題を解決します。

ALTER TABLE table ENGINE = MyISAM

または、MySQLサーバーがリリースされたら、バージョン8.0に更新します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.