web-dev-qa-db-ja.com

2つの異なるデータベース間でデータを同期する最良の方法

構造がまったく異なる2つの大きなデータベース間でデータ同期を実装する必要があります。基本的に、最初のデータベースの異なるテーブルにある製品に関するデータを取得し、それらを2番目のデータベースの他のテーブルに再配置する必要があります。

初めて製品を作成することはそれほど複雑ではありません。しかし、私は各製品に関するすべてのデータではなく特定のデータを更新する方法を探しています。

明らかに、これをトリッキーにするいくつかの問題があります。

  • 選択クエリを除いて、ソースデータベースで何もすることは許可されていません。
  • ターゲットデータベースでは、通常のクエリ(選択、更新、挿入、作成)を実行できますが、既存の構造/テーブルを変更できません。
  • ターゲットデータベースとソースデータベースの構造は完全に異なります。テーブルはまったく同じではないため、データを実際に再配置する必要があります。テーブルの比較は機能しません。
  • ターゲットデータベースはMySQLサーバーを使用します-ソースはDB2である可能性があります。
  • 「更新時間」フィールドはどこにもありません。

したがって、プロセス全体を1つのPython(理想的には)スクリプトで実行する必要があります。

ターゲットデータベースで更新するフィールドに基づいて、各製品のハッシュを作成することを考えます:md5(コード+説明+サプライヤー+約10の他のフィールド)。同じデータに基づく新しいハッシュがソースデータベースから毎日作成されます。パフォーマンスのために、すべてのハッシュを単一のテーブル(項目コード、current_hash、old_hash)に格納します。次に、新しいハッシュが古いハッシュと異なる場合は、製品を比較して更新します。

約50万商品あるので、ちょっとパフォーマンスが気になります。

それは良い方法ですか?

25
Neow

これは、私がここ数年やってきたこと、またはここ数年生きていることであり、私の直感は、ソースデータベースから500,000のアイテムを読み取って宛先で同期するのに、思ったほどの時間はかからないということです。 「キー」フィールドを読み取り、MD5ハッシュを計算し、変更されていないアイテムの同期を回避するためにテーブルをクロスチェックするのにかかる時間は、多くの時間を節約するだけでなく、実行時間も長くなる可能性があります。私は単にすべてを読み、すべてを更新します。その結果、ランタイムが長すぎる場合は、ETLをマルチスレッド化してランタイムを圧縮します。各スレッドは、テーブルのセグメントでのみ動作し、並行して動作します。

宛先データベースに主キーインデックスまたは一意のインデックスがあることを確認することが重要です。そうしないと、更新/挿入のそれぞれがテーブル全体をロックする可能性があります。これは、マルチスレッドアプローチを採用している場合は悪いことですが、シングルスレッドのままであっても重要です。ジョブが宛先DBテーブルをロックし、そのDBの上に乗っているアプリケーションに干渉する可能性があるためです。

ソースDBは「DB2の可能性がある」と言います。 「可能性があります」と言う場合、DBがまだ設計/計画されていることを意味しますか? DB2 9以降には、最終更新時間の追跡機能が組み込まれており、特定の時点以降に変更されたアイテムのみを照会して取得する機能があります。おそらくこれが、DBが最後に更新された時刻を示す列を持たないように設計された理由です。例:

SELECT * FROM T1 WHERE ROW CHANGE TIMESTAMP FOR TAB t1 > current timestamp - 1 hours;

上記のクエリのタイムスタンプカットオフは、同期が実行された最後のタイムスタンプになります。

これが事実である場合、それはあなたの問題を解決するはずです。しかし、ソリューションは結局DB2に密接に結びついてしまい、将来、別のDBプラットフォームに移動して、同期ジョブを再検討する必要がないことを期待する可能性があります。したがって、製品がDB2に依存することに依存していることをすべての適切な人々に確実に知らせることが重要です。または、移行を計画している場合、「最終変更タイムスタンプ」列を持つようにDBを再構築して、そのフィールドに入力するためにアプリレベルで必要な変更。

9
Thomas Carlisle

ある種のデルタ識別子またはフラグに基づいて実行できる場合、データの同期ははるかに優れて高速になります。基本的に、ターゲットデータベースのデータ行は、ソースデータベースと同期していない場合にのみ更新する必要があります。

SQLサーバーデータベースでは、 チェックサムfn を使用して、デルタベースの識別子を構築することもできます。

このSQLロジックを起動するには、SQLベースのジョブを開発して、昼または夜の特定の時間に呼び出す必要があります。 。データベースの使用率が非常に低い場合は、夜間のSQLジョブとして実行することをお勧めします。ソースとターゲットのdbレコードのデルタが一致しない場合は、それらのレコードのみをプルします。しかし、マイナス面は、ソースデータ行のチェックサムを毎回計算し、それをターゲットデータと比較することです。

ソースデータベーステーブルに「LastModifiedDate」のような列がある場合は、チェックサムアプローチをスキップできます。このように、評価は日付ベースの列で実行され、チェックサムアプローチと比較して時間がかかりません。

5
Karan

ハッシュの使用は良い考えです。この場合、セキュリティは目標ではないので、高速なハッシュ関数を選択します(md5で十分です)。

ハッシュ計算を複数のスレッド/プロセスに分割する予定がない限り、現在のハッシュ値をデータベースに保存する必要はありません。プロセスが単一のスクリプトの場合、メモリに現在のハッシュがあり、新しいデータベースのデータを更新した後、それを古いハッシュとしてデータベースに書き込みます。

1
Kent A.