web-dev-qa-db-ja.com

長くて幅の広いテーブル間でデータを転送するためのベストプラクティス

データウェアハウスプロジェクトの一部として、OLTPからデータウェアハウスにデータを転送します。一部のテーブルは長くて広いので、明らかに、必要な列のみを転送します。

オーバーヘッドを減らすために、これらのテーブルでのデータ追跡を検討しているので、テーブル全体をスキャンするのではなく、変更された値のみを調べます。残念ながら、ソースシステムはSQL Server 2014 Standard Editionで実行され、CDCは利用できないオプションです。

変更の追跡よりも優れた代替方法はありますか?

2
Krishn

ソーステーブルに '' rowversion ''列を追加することを検討しましたか?

rowversion(以前のSQL Serverではtimestamp)について考える最も簡単な方法は、データベース全体の自動番号として使用することです。 INSERT、UPDATE、またはDELETEを実行するたびに、データベース全体の行バージョンが増加します。 rowversion列が定義されているテーブルでは、関連する行がINSERTまたはUPDATEされたときに、その列の値がデータベースの行バージョンに設定されます。

これを使用するための簡単なアルゴリズムを次に示します。

  • データベース全体のrowversion値を保存します(@@DBTSを介して使用できます。つまり、DataBase TimeStamp
  • データをデータウェアハウスに処理する
  • 次回は、rowversion値が以前に保存された@@DBTSより大きい行のみを処理します

処理する必要のある行を見逃してはいけませんが、実際にデータを変更せずに行を再処理できます。これは、データが現在の値に「rowversiond」で実際には変更されていない場合でも、UPDATEUPDATEステートメントごとに増分されるためです。

また、どのcolumnsが変更された可能性があるかを特定するのにも役立ちません。名前が示すように、行レベルで厳密に機能します。

3
mwolfe02

私には、SQL Serverの標準エディションには2つの潜在的な方法があります

  1. 変更を追跡するトリガーを作成します(ワークロードをテストして、トリガーがパフォーマンスに影響するかどうかを確認できます)

または

  1. OLTPテーブルをほぼリアルタイムでDWテーブルに転送する必要がないと仮定すると、1時間ごとにスナップショットを作成し、CLRストアドプロシージャを使用して、各行のハッシュ値を計算できます。スナップショットデータベースと現在のデータベースの両方で対象となるテーブル、および主キーを使用して変更された行をすばやく見つけ、対応するOLAPテーブルを挿入/更新/削除します。
2
jyao

一般的に言って、データベースシステムベンダーが提案するソリューションを使用することが非常に望ましいと私は思います。クライアント側にRI(Referential Integrity)を実装することに関する状況は思い浮かびます-そして、軽減されていない災害のレシピです-ポストへの私の答えを読んでください here その特定のワームの缶について!

"Debezium"(RedHatでサポートされているCDCプロジェクト。 herehere を参照)を確認することをお勧めします。残念ながら、 SQL Serverコネクタはアルファ版のみです ですが、プロジェクト全体への最後のコミットは7日前しかなかったため、アクティブです。いつでも質問できます。

そうは言っても、DebeziumはRedHatによってサポートされています。これは常に良い兆候ですが、Apache Kafka-それ自体が複雑なシステムをセットアップすることを伴います。

もし私があなただったら、私は慎重にトラブルに行くことのコスト/利益分析(工数、バグの可能性があってもSQL Serverコネクターは、独自のロールソリューションをセットアップする(OK、それはRedHatですが、それでも...)か、Microsoft自体の標準のソリューションを使用することで、アルファ版から抜け出します。

興味深い記事(LinkedInのMySQLソリューションについて) here および here 最後のコミットは1年以上前だったので、プロジェクトがどれほどアクティブであるかわかりません。 m近いうちにSQL Serverが実行されないことを確信しています。

1
Vérace

増分変更を行うために、ソーステーブルに「最高水準点」列を追加できます。この列には、最後の挿入/更新のdatetimeが格納されます。

つまり、DtLastUpdateのデフォルトのGETDATE()という列と、更新後にトリガーを作成して、この値が各更新後にGETDATE()の値を受け取ることを保証できます。

増分ロードを行う場合、この列をフィルターとして使用できます。

where DtLastUpdate > @dtIncremental

この例では、@dtIncrementalは、最後に正常にロードが開始された日付を表します-デルタ(datetimeフィールドの量と精度に応じて、1分から1日になる可能性があります)

もちろん、このトリガーはオーバーヘッドを引き起こす可能性がありますが、通常は小さいものです。

利点

  • 通常、変更の追跡には少し時間がかかります。エラーにより、より長い期間をリロードする必要がある場合は、変更追跡で全負荷を実行する必要があります

  • 同じロジックがフルまたはインクリメンタルロードに適用されると、ETLはより単純になります(@dtIncrementalパラメーターのみを変更する必要があります)

短所

  • ソーススキーマを変更する必要がある(常に実行可能とは限らない)

  • 削除を追跡しません-しかし、同様のアプローチで追跡できます

まあ、でもそれは良いですか? ->私はあなたと結論を出しました。特に、ソースシステムに「ハイウォーターマーク」列がなく、そのスキーマを変更できない場合は、変更追跡を使用します。

1