2012-04-14 28 views
1

私はワークスペースAとワークスペースBにデータベースを持っています。 オンラインこのデータベースのコピーは常に両方のワークスペースから更新されています。 また、両方のワークスペースは、他のワークスペースが変更を加えるたびにデータベースを更新する必要があります。2つのデータベースを外部キーとマージするときのSQLの問題

すべてがうまく機能しているが、私の問題はこれです:たとえば2つのテーブルStockOrdersOrdersに、あるstock_idある列があります。

ワークスペースAが自動的に "stock_id" = 23の増分で新しい "ストックX"を作成し、ワークスペースBが自動的に増分された "stock_id" = 23で新しい "在庫Y"を作成すると、ワークスペースBはワークスペースAの " 「ストックX」を選択し、ワークスペースBはワークスペースBの「ストックY」を追加しますが、各データベースには異なるIDが割り当てられます。

この問題は、このクエリーがセントラルデータベースに送信され、ワー​​クスペースBに送信されたときに在庫番号が23の「在庫X」という注文をしたときに発生します。 「在庫Y」を参照します。

私はこのおかげでいくつかの助けを本当に感謝:)

答えて

2

EDITED:主キーの

あなたのオリジナルのデザインを使用AUTO INCREMENT列。この問題は、最終的にマージされる別々のデータベースに同時にデータが入ったときに表示されるようになると、重複するキーが作成されることになります。

各代替データベースでシーケンスを使用することもできます。残念ながら、シーケンスはmysql(Oracleなどの他の多くのデータベース、db2はそれらを持っています - このタイプの分散データベースの挿入は衝突なしで可能です)ではネイティブに利用できません。 AUTO INCREMENT列では、必要なレプリケーションの種類が許可されません。

これで2つのオプションが残っています。

1)(最初の回答ごとに)location_idを設定する主キーの余分な部分を追加します。

2)AUTO INCREMENT列を使用するのではなく、独自のシーケンスを使用して手動でIDを生成します。

それは、シーケンス内の次の値を取得するときに自分自身をコミットするストアドプロシージャ/ファンクションとしてシーケンスを実装するためにおそらく最高だ - これが使用されていない値になってしまうことがあります。これは問題ありません。挿入物全体がコミットされるまでシーケンス番号をコミットするのを待つ場合は、競合よりも優れています。

主なものは、あなたが最初のインサートをやっているとき、あなたはストアドプロシージャからのシーケンス番号を使用することです。データを2番目のdbに効率的に複製すると、元のdbの行に生成されたシーケンス番号が使用されます。そして、シーケンスは、衝突を防ぐために、異なる開始点を持つそれぞれの別々のdbに維持されるだろう。

例えば、各データベースには、次の2個のピース​​をしたいと思う:

1)各名前のシーケンスの次の使用可能なシーケンス番号を保持するテーブル。 (シーケンスから抽出された主キーを取得する各テーブルはエントリを取得します)。 2)次のシーケンス番号を持つテーブルにアクセスして更新する関数。

サンプルの実装は次のようになります。

シーケンステーブル:

CREATE TABLE sequences (
    name varchar(30) NOT NULL, 
    value int(10) unsigned, 
    PRIMARY KEY (name) 
) ENGINE=InnoDB 

シーケンス機能(S):

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 ; 

主な問題は、格納された機能が単一である必要があるということですそれが完了してすぐにコミットするようにします(そうでなければ、注文が入ったときにトランザクションが互いに後ろに積み重なるようにロックします)。y非常に高いスループットを持っていませんが、これは問題ではありません。

私はこの関数を書いていない - 私は自由にここからそれをコピーしている:私はより多くの詳細については、にあなたを参照することになり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> 

-

I Hこのソリューションを道路でテストしてはいけません - シーケンスに関する私の答えに示唆していることの概要としてそれを取ってください。上記のブログエントリのリンクをフォローアップする必要があります。具体的には、トランザクション制御下でのこの作業の仕組み、コメント(コメントから関数の形式を取ったもので、元の関数ではありません)もちろん、負荷をかけてテストしてください。

+0

私は衝突に遭遇することはないと確信していますが、少なくとも光の2年前ではありません。しかし、異なる自動インクリメントのルートを割り当てることは私の問題を解決するつもりはありません。 例:structure:Stock(s_id、s_name)注文(o_id、s_id、金額) ワークスペースAは新しいアイテムs1を挿入し、自動インクリメントs1.s_id = 1を割り当てられます。 s_id = 1、これら2つの問合せを作業領域2に送信すると、それは在庫s1を挿入し、自動インクリメントs1.s_id = 100000が割り当てられ、2番目の問合せ「insert into Orders(s_id)values(1)」を実行します。 。私は論理的な解決策がないと思う。 – Haz

+0

私の謝罪 - 改訂版の回答を見てください。私はmysqlの用語ではなく、db2の言葉(私の現在のクライアント)を考えています。そして、一般的に、はい、この問題に対する論理的な解決策があります.Wi-Fiや普及しているインターネット接続の前の日には、dbを配布し、後でデータをマージする必要があったのです。したがって、マージ時の衝突を避けるためのスキームがたくさんあります。 –

+0

はい、私は興味があります。私は少し失われた小さな例に感謝します。そして、私が下に出てきたことについてのあなたの考えを感謝します。 – Haz

2

ワークスペースAとBがそれぞれID 23に対して異なるエントリを持っている場合は、あなたの唯一のオプションは、レコードがある場合に、各エントリの二次キーを作成することです中央のDBに更新されました。このキーは、ワークスペースデータベースを更新するときにワークスペースデータベースに再コピーすることができ、アイテムに本当に一意の識別子でアクセスできるようになります。

ただし、この方法を使用しないことを強くお勧めします。

作業を行う適切な方法は、ワークスペース1と2で使用されるWebアプリケーションまたはデスクトップアプリケーションを作成し、中央データベースに接続してすべてのデータアクセスに使用することです。優れたデータベース設計とは、一般的に、できるだけ複製データを複製することを意味します。 3つの異なるデータベースで注文、在庫などを複数回コピーすることにより、将来のデータ破損および/または損失のために自分自身を設定しています。データベースが大きくなるにつれて修復が難しくなる問題サイズ。データベースのサイズが大きくなる前に構造上の問題を修正してください!

+0

私はあなたのセカンダリキーソリューションの簡単な例を教えてください。 私はセントラルデータベースを使用しますが、ワークスペースはLANではなくインターネットを介して接続されているため、時間差がありません。私のデータ構造に関しては、おそらく単純に外部キーの例として実装されているようにすることができます。在庫(株価、名前など)注文(o_id、株価、金額など)。あなたは何をお勧めしますか?もう一度ありがとう – Haz

+0

私は問題を再検討し、ここで私はあなたに何を与えることができます。私の元々の解決策はid_localとid_globalという2つのIDを持つことでした。 Id_localはレコード作成時にローカルデータベースに自動的に割り当てられます。 Id_globalは、レコードがコピーされるときにグローバルデータベース内で自動的に割り当てられます。更新が行われるたびにレコードがワークスペースデータベースに更新されると、このid_globalはそれらのデータベースにも残ってしまい、各レコードを一意に識別することができます。次のコメントの他の解決策。 –

+0

私の他の解決策は、id_workspaceに作業領域ID列と複数列のキーがあり、自動割り当てアイテムIDを持つことです。このように、ワークスペース1と2は、重複しているids/pksを持たずに同じ値を自動的に割り当てることができます。これは、ワークスペースIDカラムで一意に識別されるためです。私は実際には、できるだけ集中管理されたデータベースソリューションを実装することをお勧めします。なぜなら、何かがすぐに中断し、不幸な顧客を残してしまうからです。それはあなたが絶対にそれをすることができない場合、このアイデアはあなたのために働くことになるかもしれません。 –

0

上記の他のソリューションと比べて、それで行くことにその優れた場合、私はイムはまだ混乱してこの答えを考え、しかし。 ワークスペースB内のすべてのクエリは、ローカルデータベース上で一時的に実行され、中央データベースに送られてからワークスペースAに送信されますが、ワークスペースAのクエリはローカルデータベース上でimmidiatly実行されません。セントラルはそれらをワークスペースBに送り、ワークスペースBがこれらのクエリを実行すると、セントラルに通知し、ワークスペースAに通知された後、格納されたクエリを実行することができる。そのようにして、作業領域Bはその問合せを通常通り実行することができますが、作業領域Aは、作業領域Bがそれらの問合せを実行した時点を知っているときのみ、その問合せを実行できます。クエリがAのクエリを実行するので、Bがクエリを実行したことがAに通知された後、Bがそれ自身の新しいクエリを送信して実行し、それを実行してから、それ自身のクエリを実行するかどうかをチェックします。そうすれば、すべての自動認識されたIDは両方のワークスペースで同じになります。例:

ワークスペースA:

  q1= insert into stock (name) values ('A') not executed 

     q2= insert into stock (name) values ('B') not executed 

のデータベース:(空)

作業領域Aの中央にQ1 & Q2を送信し、そのBを確認するために、中央のを待っているので、これらのクエリを実行しました

  q3= insert into stock (name) values ('C') executed id=1 

     q4= insert into stock (name) values ('D') executed id=2 
:それは

ワークスペースBそれらに自身を実行することができますBの3210

データベース:(1、 'C')、(2、 'D')

作業領域Bは、中央にQ3 & Q4を送信した後、それは、Q1、Q2の

作業領域Bの実行を通知しますQ1 & Q2

  q1= insert into stock (name) values ('A') executed id=3 

      q2= insert into stock (name) values ('B') executed id=4 

データベースB:(1、 'C')、(2、 'D')、(3、 'A')、(4、 'B')

ワークスペースA Bがq1 & q2を実行したことが通知されますが、q3を実行する必要があることが通知されますQ4がQ1 & Q2を実行する前に

ワークスペースA:Bの

  q3= insert into stock (name) values ('C') executed id=1 

      q4= insert into stock (name) values ('D') executed id=2 

      q1= insert into stock (name) values ('A') executed id=3 

      q2= insert into stock (name) values ('B') executed id=4 

データベース:(1、 'C')、(2、 'D')、(3、 'A') 、(4、 'B')

+0

上記の私の主なコメントは、あなたのアーキテクチャを直接コードに焼くことです。これは非常に拡張性が高く/柔軟ではありません。上記の両方のソリューションは、異なる方向性を持ち、複数の分散データベースに拡張可能です。そして、いずれかのデータベース(すべてが統合される中央データベースを含む)がダウンしていても、いずれも悪影響を及ぼすことはありません。どのように行っても、1 db、2 db、および10 dbで動作するかどうか、これらの条件で考えてください。そして、1つ以上のデータベースがダウンしたときにはどうなりますか? –

関連する問題