これは、SELECTの実行中にmy_tblに共有ロックを作成するため、適切なソリューションではありません。任意の数のスレッドが同時に共有ロックを持つことができますが、同時書き込みロックをブロックします。したがって、これにより挿入がシリアル化され、SELECTが終了するのを待ちます。
このロックを観察できます。このクエリを1つのセッションで開始します。
INSERT INTO my_tbl (idx, clmn_1)
SELECT IFNULL(MAX(idx), 0) + 1, 1234+SLEEP(60)
FROM my_tbl;
次に、別のセッションに移動してinnotopを実行し、ロック画面を表示します(キー「L」を押します)。次のような出力が表示されます。
___________________________________ InnoDB Locks ___________________________________
ID Type Waiting Wait Active Mode DB Table Index Ins Intent Special
61 TABLE 0 00:00 00:00 IS test my_tbl 0
61 RECORD 0 00:00 00:00 S test my_tbl PRIMARY 0
これが、自動インクリメントメカニズムがそのように機能する理由です。トランザクションの分離に関係なく、挿入スレッドは、自動インク番号をインクリメントするためにのみテーブルを一時的にロックします。これは非常に高速です。次に、ロックが解除され、他のスレッドがすぐに続行できるようになります。その間、最初のスレッドは挿入を終了しようとします。
自動インクリメントロックの詳細については、http://dev.mysql.com/doc/refman/5.5/en/innodb-auto-increment-handling.htmlを参照してください。
列を自動インクリメント列として定義するだけでなく、自動インクリメントの動作をシミュレートする理由がわかりません。 既存のテーブルを変更して自動インクリメントすることができます。
コメントを再確認してください。
PKが自動インクリメントとして宣言されている場合でも、値を指定できます。自動インクリメントは、INSERTでPK列を指定しないNULL
場合、または値としてまたはを指定した場合にのみ開始DEFAULT
されます。
CREATE TABLE foo (id INT AUTO_INCREMENT PRIMARY KEY, c CHAR(1));
INSERT INTO foo (id, c) VALUES (123, 'x'); -- inserts value 123
INSERT INTO foo (id, c) VALUES (DEFAULT, 'y'); -- inserts value 124
INSERT INTO foo (id, c) VALUES (42, 'n'); -- inserts specified value 42
INSERT INTO foo (c) VALUES ('Z'); -- inserts value 125
REPLACE INTO foo (id, c) VALUES (125, 'z'); -- changes existing row with id=125
コメントを再確認してください。
START TRANSACTION;
SELECT IFNULL(MAX(idx), 0)+1 FROM my_tbl FOR UPDATE;
INSERT INTO my_tbl (idx, clmn_1) VALUES (new_idx_val, some_val);
COMMIT;
これは実際には最初のアイデアよりも悪いです。これはSELECT...FOR UPDATE
、がSロックではなくXロックを作成するためです。
SQLソリューションはACIDプロパティによって制限されるため、AUTO-INCREMENTの動作を再発明しようとしないでください。Auto-incは必然的にACIDの外部で機能します。
既存の行をアトミックに修正する必要がある場合は、REPLACEまたはINSERT ... ON DUPLICATEKEYUPDATEのいずれかを使用します。