web-dev-qa-db-ja.com

異なるテーブルのデータを1つに集約することはお勧めできませんか?

背景

私は多くの大きなレポートを書き、一般的に大きなヘルスレコードDBを維持しています(SP、関数、ジョブなどを書き込みます)。元のスキーマとそれを使用するソフトウェアは別のベンダーのものであるため、構造についてはあまり変更できません。ラボ、手順、ワクチンなど、追跡が必要なレコードは多数あり、それらは数十のテーブルに散らばっており、それらの多くは肥大化しており、インデックスが不十分です(これは多少修正できました)。

問題

問題は、DBをほとんど制御できないため、特定の更新またはパッチから変更される可能性があるため、特にオーバーラップが大量にある場合に、これらのレポートの作成と保守が困難で面倒なことです。必要なのは1つのパッチだけであり、12のレポートの大部分を書き換えるのに行き詰まっています。さらに、結合、ネストされた選択、および適用が積み重なると、クエリはすぐに難読化されて遅くなります。

私の「解決策」

私の計画は、これらのレコードをすべて1つの「キャッチオール」テーブルに書き込み、元のテーブルにトリガーを書き込んで、この集計テーブルのレコードを維持することでした。もちろん、更新後もトリガーが損なわれていないことを確認する必要がありますが、これは保守性の観点から見るとデータを参照するだけの方がはるかに簡単です。

テーブルは薄くて長く、必要なデータのみを格納します。たとえば、次のようになります。

CREATE TABLE dbo.HCM_Event_Log (
    id INT IDENTITY,
    type_id INT NULL,
    orig_id VARCHAR(36) NULL,
    patient_id UNIQUEIDENTIFIER NOT NULL,
    visit_id UNIQUEIDENTIFIER NULL,
    lookup_id VARCHAR(50) NULL,
    status VARCHAR(15) NULL,
    ordered_datetime DATETIME NULL,
    completed_datetime DATETIME NULL,
    CONSTRAINT PK_HCM_Event_Log PRIMARY KEY CLUSTERED (id)
)

次に、type_idやアイテムグループなどのさまざまなリレーショナルテーブルを用意します。

これらのテーブルのいくつかはかなり書かれているので、私はこの考えを2番目に推測し始めています。私が書いているSPとレポートもデータをたくさん参照するでしょう。したがって、このテーブルが大量のI/Oを伴うレコードのロックとパフォーマンスの悪夢になることを心配しています。

私の質問

悪いアイデアですか、それとも良いアイデアですか? SQL Server(2008 r2 Standard Edition BTW)と "ときどき"のルールではすべての状況が異なることに気づきましたが、私は本当に一般的なアドバイスを探しています。

サービスブローカーの使用を検討し始めましたが、単純な更新/挿入のみを実行することになります( 承認された回答の代替案を参照 )。多くの場合、データはリアルタイムである必要があるため、バックアップDBを使用しても実際には機能しません。パフォーマンスはすでにいくらか問題になっていますが、そのほとんどはハードウェア関連であり、すぐに解決される予定です。

12
jreed121

私があなたを正しく理解していれば、

  • 大規模なサードパーティシステムがあり、
  • あなたはそれをあまり制御できません
  • このサードパーティのデータベースから直接データを読み取る複雑なレポートを作成し、
  • クエリは、サードパーティデータベースの内部構造に依存します。

私はこのようにそれに取り組みます:

  • 自分で完全に制御できる独自のデータベースをセットアップします。
  • サードパーティのデータベースから関連するテーブルと列からデータを読み取り、鉱山に挿入/更新する同期プロセスを設定します。
  • データベースの安定した構造に基づいて、複雑なレポートを作成します。

この場合、サードパーティのシステムに影響を与えることなく、データベースの構造とインデックスを微調整して、レポートのパフォーマンスを向上させることができます。元のデータ構造が大幅に変更されない限り、サードパーティのデータベースが変更されても、レポートのクエリのロジックは変更されません。同期プロセスのみを調整する必要があります。

同期プロセスは実質的にconversionプロセスです-サードパーティのデータベースのデータを必要な構造に変換します。この変換プロセスの一部は、元のサードパーティデータベースにあった正規化の問題を修正している可能性があります。システムのこの部分だけが、サードパーティシステムの内部構造を認識して依存する必要があります。メインレポートとメインクエリは、データベースにのみ依存します。

したがって、要点は、サードパーティシステムの内部に依存するシステムの部分を分離して制限することです。

更新

リアルタイム要件について。ところで、「リアルタイム」の定義は「保証された応答時間」であり、「多少の応答時間」ではないと常に思っていました。もちろん、アプリケーションによって異なります。私の実践では、検出された変更から1分以内に2つのデータベースを同期すれば十分です。画面にレポートが表示され、基になるデータが変更された場合、この変更を反映するためにレポートを何らかの方法で再実行する必要があります。変更をポーリングするか、イベント/メッセージをリッスンできますが、最新の変更を表示するには、レポートクエリを再度実行する必要があります。

元のテーブルの変更をキャプチャーするトリガーを作成し、これらの変更を1つの汎用テーブルに書き込む予定です。したがって、意図したとおりに変更をキャプチャしますが、単一のテーブルではなく、適切に正規化されたテーブルに変更を書き込みます。

したがって、これは極端なケースです-サードパーティのデータ構造の内部データ構造への変換は、サードパーティのテーブルのINSERT/UPDATE/DELETEで発生するトリガーで実行されます。トリッキーになる可能性があります。トリガーのコードは、両方のシステムの内部構造に依存します。変換が重要な場合、元のINSERT/UPDATE/DELETEが失敗するまで遅延する可能性があります。トリガーにバグがあると、元のトランザクションに影響を与え、失敗する可能性があります。サードパーティシステムが変更されると、トリガーが壊れ、サードパーティシステムのトランザクションが失敗する可能性があります。

それほど極端ではないケース。トリガーのコードをよりシンプルにし、エラーが発生しにくくするために、キャプチャされたすべての変更をステージング/監査/差分テーブルに書き込み、いくつかのフラグを設定する/保留中の変更があることを示すメッセージを送信し、実行されるメインの変換プロセスを起動するこれらの中間テーブルを介して変換を実行します。ここで重要なことは、潜在的に重い変換プロセスが元のトランザクションの範囲外で発生することです。

一見すると、質問の元の提案とほとんど同じです。ただし、違いは次のとおりです。すべてをキャプチャするテーブルは一時的にのみデータを保持します。データの量が少ない-何が変わったか。単一のテーブルである必要はありません。最終的に、データは、適切に正規化された個別の永続テーブルに格納されます。これらのテーブルは完全に制御でき、サードパーティシステムから独立しており、クエリに合わせて調整できます。

8

私は過去に24時間年中無休の製造会社でこのような非常に類似した状況で作業し、最終的にトランザクションレプリケーションを使用することを決定しました。 可能です パッチが変更された場合にサブスクライバーにプッシュアウトできるように、DDLが複製されるように構成します。明らかにすべてに長所と短所があり、会社に最適なものに対してサポートできるものを決定するためにそれらを比較検討する必要があります。

良い面:

  1. 「リアルタイム」は、サブスクライバーでのネットワークおよびトランザクションのコミットパフォーマンスにのみ制限されます。適度に高いTPSシステムでの私の経験では、「リアルタイム」のデータから10秒以内に複製されました。
  2. ワークロードの分離。現在、1台のサーバーで混合ワークロードを実行しています。これらの2つの懸念を分離できる場合、方程式から1つのワークロードを削除したことにより、両方のシステムでパフォーマンス上の利点を得ることができる可能性があります。
  3. コントロール。レポートのワークロードに合わせて、インデックス作成/統計/メンテナンスの変更を行うことができます。

ただし、短所もあります。

  1. 費用。別のライセンスと追加のハードウェア(仮想またはその他)。
  2. レプリケーション。適切に設定されていれば問題なく動作しますが、その時点まで到達するのは面倒です。
  3. メンテナンス。構造に有害な変更(インデックスの削除など)を行った場合、スナップショットが適用されると(パブリケーションが変更された後、またはアーティクルが変更されたときに)構造が返されます。
3
swasheck

複雑なレポートやクエリを変更する必要がなく、インポートステージを微調整できるように、必ず標準化されたテーブルのセットに入れてください。しかし、データはまだ正規化されている必要があり、複数のテーブルが必要になります(ただし、インデックスは適切です)。

他の人が述べたように、トリガーを使用しないで、バッチで同期します。

多数の結合について心配する必要はありません。データが正常に正規化され、適切にインデックスが付けられている場合、これらは大きなコストや管理負担を追加しません。

データウェアハウスのようなものに非正規化する時期は、予測できないデータに対してさまざまな種類のクエリを数多く実行できるようにする必要があるときです。独自の欠点とオーバーヘッドがあり、頼りになるものとしてではなく、適切な場所で使用する必要があります。

3
JamesRyan

私の計画は、これらのレコードをすべて1つの「キャッチオール」テーブルに書き込み、元のテーブルにトリガーを書き込んで、この集計テーブルのレコードを維持することでした。

トリガーには非常に多くの問題があるため、回避する必要があります。

  • トリガーのエラーにより、元のトランザクションが中止される可能性があります
  • 複数行の操作を正しく処理するトリガーを書くのは難しい
  • トリガーは、返された行セットを変更することでクライアントアプリケーションを混乱させる可能性があります(たとえば、トリガーは影響を受ける行の数をオーバーライドします)
  • あるトリガーが別のトリガーをトリガーするとき、結果を予測するのは難しい

より良いオプションは、定期的にデータを新しいテーブルにコピーするジョブです。レポートでコピーを実行できます。行をコピーするジョブは、書き込みと保守が簡単であり、サードパーティアプリケーションの動作に影響を与えるリスクはありません。

2
Andomar