MySQLでトランザクションセーフなシーケンスをエミュレートする
-
03-07-2019 - |
質問
MySQLをInnoDBストレージエンジンとトランザクションで頻繁に使用しており、問題に直面しました。OracleのシーケンスをMySQLでエミュレートする良い方法が必要です。要件は次のとおりです。 -並行性サポート -トランザクションの安全性 -最大パフォーマンス(ロックとデッドロックの最小化を意味します)
一部の値が使用されないかどうかは関係ありません。つまり、シーケンスのギャップは問題ありません。カウンターを備えた別のInnoDBテーブルを作成することで、これを実現する簡単な方法がありますが、これはトランザクションに参加し、ロックと待機を導入することを意味します。手動ロック、他のアイデア、またはベストプラクティスを使用してMyISAMテーブルを試すことを考えていますか?
解決
自動インクリメントでは十分でない場合は、次のような名前付きシーケンスで n アトミックシーケンスメカニズムを作成できます。
シーケンスを保存するテーブルを作成します:
CREATE TABLE sequence (
seq_name varchar(20) unique not null,
seq_current unsigned int not null
);
テーブルに「foo」の行があると仮定すると、次のように次のシーケンスIDをアトミックに取得できます。
UPDATE sequence SET seq_current = (@next := seq_current + 1) WHERE seq_name = 'foo';
SELECT @next;
ロックは必要ありません。どちらのステートメントも同じセッションで実行する必要があるため、選択が発生するとローカル変数@nextが実際に定義されます。
他のヒント
これを行う正しい方法は、に記載されています。 MySQLマニュアル:
UPDATE child_codes SET counter_field = LAST_INSERT_ID(counter_field + 1);
SELECT LAST_INSERT_ID();
私たちは高トランザクションゲーム会社であり、私たちのニーズに合わせてこの種のソリューションを必要としています。 Oracleシーケンスの機能の1つは、設定可能な増分値でもありました。
ソリューションでは、 DUPLICATE KEY
を使用します。
CREATE TABLE sequences (
id BIGINT DEFAULT 1,
name CHAR(20),
increment TINYINT,
UNIQUE KEY(name)
);
次のインデックスを取得するには:
ストアドプロシージャまたは関数 sp_seq_next_val(VARCHAR)
を使用して以下を抽象化します。
INSERT INTO sequences (name) VALUES ("user_id") ON DUPLICATE KEY UPDATE id = id + increment;<br/>
SELECT id FROM sequences WHERE name = "user_id";
テーブルのMySQL Identityカラムはこれを処理しませんか?
CREATE TABLE table_name ( id INTEGER AUTO_INCREMENT PRIMARY KEY )
または、別のテーブルに挿入する以外の目的で使用する予定ですか?
(SQLだけでなく)手続き型言語を使用して記述している場合、他のオプションは、単一の整数(または長整数)値とそれをロックするストアドプロシージャを含むテーブルを作成することです。値を返す前に、インクリメントしてロックを解除しました。
(注-値を返す前に常に増分します-エラーがある場合に重複が発生しないようにするか、トランザクション全体をラップします。)
次に、メインの挿入/更新とは別にこれを呼び出して(呼び出しメカニズムによって自動的に作成されたトランザクションに巻き込まれないようにします)、使用する場所にパラメーターとして渡します。
それはあなたがやっている他のことから独立しているので、速くてロックの問題を避けるべきです。ロックが原因でエラーが発生した場合でも(データベースをオーバーロードしていない限り)、2回目/ 3回目で呼び出すことができます。