編集:
元のデザインAUTO INCREMENT
では、主キーに列を使用していました。これに伴う問題は、最終的にマージされる別々のデータベースに同時にデータが入る場合に見られるように、重複するキーを作成してしまうことです。
別の方法の1つは、個別のデータベースごとにシーケンスを使用することです。残念ながら、シーケンスはmysqlでネイティブに使用できません(Oracle、db2などの他の多くのdbにはシーケンスがあります。これらは、衝突なしでこのタイプの分散データベース挿入を許可します)。 AUTO INCREMENT
列は、必要な種類のレプリケーションを許可しません。
したがって、2つの選択肢があります。
1)location_idを設定する主キーの余分な部分を追加します(最初の回答に従って)。
2)または、列を使用するのではなく、独自のシーケンスを使用して手動で挿入のIDを生成しAUTO INCREMENT
ます。
シーケンスの次の値を取得したときにそれ自体をコミットするストアドプロシージャ/関数としてシーケンスを実装するのがおそらく最善です。これにより、値が使用されなくなる可能性があります。それは問題ありません。挿入全体がコミットされるまでシーケンス番号をコミットするのを待つ場合は、競合よりも優れています。
主なことは、最初の挿入を行うときに、ストアドプロシージャのシーケンス#を使用することです。データを2番目のデータベースに効果的に複製する場合、元のデータベースからの行で生成されたシーケンス#を使用します。また、衝突を防ぐために、シーケンスは異なる開始点を持つ各個別のデータベースで維持されます。
たとえば、各データベースで、次の2つの部分が必要になります。
1)名前付きシーケンスごとに次に使用可能なシーケンス番号を保持するテーブル。(シーケンスから引き出された主キーを取得する各テーブルはエントリを取得します)。2)次のシーケンス番号でそのテーブルにアクセスして更新する関数。
実装例は次のとおりです。
シーケンステーブル:
CREATE TABLE sequences (
name varchar(30) NOT NULL,
value int(10) unsigned,
PRIMARY KEY (name)
) ENGINE=InnoDB
シーケンス関数:
delimiter //
create function get_next_value(p_name varchar(30)) returns int
deterministic
sql security invoker
begin
declare current_val integer;
UPDATE sequences
SET value = (@current_val:=value) + 1
WHERE name = p_name;
return @current_val;
end //
delimiter ;
主な問題は、ストアド関数が単一のステートメントである必要があることです。これにより、関数は完了し、すぐにコミットされます(そうしないと、注文が入ったときにトランザクションが互いにスタックするようにロックされます。スループットがそれほど高くない場合、これはそれほど問題にはなりません。
私はこの関数を作成しませんでした。詳細については、http://www.bigdbahead.com/?p=185 を 参照してください。(そして、そのユーザーがここで私を見つけた場合、私は彼に答えを書かせて、ここでも適切なクレジットを与えることができます)。
ここで、データベースごとに、衝突を回避するために異なる番号で値を初期化します。したがって、orders
テーブルの場合、場所Aで、これを次のように初期化します。
insert into sequences ('orders', 1);
場所Bでは、これを次のように初期化します。
insert into sequences ('orders', 1000000);
そして、両方のデータベースで、に挿入するorders
と、次のようになります。
insert into orders (order_id, . . .)
select mysql.get_next_value('user_id'), . . . <hardcoded-values>
-
私はこのソリューションをロードテストしていません-シーケンスに関する私の答えで私が提案していたことの概要としてそれをとってください。上記のブログエントリリンクをフォローアップする必要があります。これは、特にトランザクション制御下でこれがどのように機能するかについての詳細を提供します。コメントを参照してください(元の関数ではなく、コメントから関数の形式を取得しました) 、そしてもちろん、負荷がかかった状態でテストします。