2012-01-24 5 views
3

InnoDBの挿入に失敗すると、自動インクリメントの主キーにギャップが生じるという事実に慣れていますが、これは無関係です(私には分かりません)。私が抱えている問題は、プライマリキーに5から8までのギャップを持つ自動増分プライマリキーを持つテーブルに5つのレコードを挿入することです。ここで問題を繰り返すスクリプトがあります。INNODBのバルク挿入により、自動インクリメント主キーが値をスキップするのはなぜですか?

DROP TABLE IF EXISTS `test_table`; 
CREATE TABLE `test_table` (
`A` int(10) unsigned NOT NULL AUTO_INCREMENT, 
`B` int(10) unsigned NOT NULL, 
PRIMARY KEY (`A`) 
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; 

insert into `test_table` (`B`) 
SELECT 1 
UNION 
SELECT 2 
UNION 
SELECT 3 
UNION 
SELECT 4 
UNION 
SELECT 5; 

insert into `test_table` (`B`) 
SELECT 6 
UNION 
SELECT 7 
UNION 
SELECT 8 
UNION 
SELECT 9 
UNION 
SELECT 10; 

SELECT * FROM `test_table`; 

私は両方の列AとBは、このケースで同じになるように、2番目のインサートAの先頭に8になり、Bは6になります期待し、このギャップが発生した理由を誰もが知っていますか?

私はここでドキュメントを見てきました:http://dev.mysql.com/doc/refman/5.1/en/innodb-auto-increment-handling.htmlしかし、これらのロックモードはこのギャップに関係していないようです(何か不足している可能性があります)。何らかの理由

答えて

1

私は、クエリアナライザが内部クエリによって返される行の数を概算するように求められていたと思います。

データベースエンジンは、3つの相反する目標のために努力する必要があります。

  • トランザクションがアトミックである必要があり、そのトランザクション内のシーケンスから生成された任意の番号が連続している必要があります。
  • 配列が長時間量のためにロックされてはならない(そうでなければ、他のINSERT操作がブロックされる)、
  • ことがなくてもよいように、内側のクエリは、完全な結果表を実現する必要はありません大。

保証されたシーケンス番号がグローバルに連続することは保証されていないので、挿入する必要がある行数の上限を取得し、その量だけシーケンスを(アトミックに)インクリメントし、 INSERT操作のために予約されています。

これは、並行INSERTがより小さいか大きい主キー値を持つことを保証します(つまり、問合せは適切に直列化されます)が、行間にデータを追加できます(ORDER BY句を使用しない限り)

4

'test_table INTO(B)を挿入1 UNION SELECT 2 SELECT' はAUTO_INCREMENT = 4で設定したが、予想通り、これは作業を挿入 -

INSERT INTO `test_table` (`B`) 
VALUES (1), (2), (3), (4), (5); 

INSERT INTO `test_table` (`B`) 
VALUES (6), (7), (8), (9), (10); 

= 0 innodb_autoinc_lock_mode及び実行を設定してみてくださいあなたのスクリプトをもう一度、ギャップがないでしょう。

AUTO_INCREMENT Handling in InnoDB