異なるテーブルのデータを1つに集約するのは悪い習慣ですか?


12

バックグラウンド

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

問題

問題は、DBをほとんど制御できないため、また特定の更新やパッチから変更される可能性があるため、これらのレポートの作成と保守が困難で面倒になることです(特に重複が多い場合)。必要なのは1つのパッチだけで、多数のレポートの大部分を書き直しています。さらに、結合、ネスト、選択、適用が積み重なると、クエリはすぐに難読化され、遅くなります。

私の「解決策」

私の計画は、これらすべてのレコードを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やアイテムのグループ化などのさまざまなリレーショナルテーブルを作成します。

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

私の質問

悪いアイデアですか、良いアイデアですか?SQL Server(2008 r2 Standard Edition BTW)と「ときどき」ルールでは状況はすべて異なりますが、一般的なアドバイスを探しているだけです。

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


1
計画停止を実施できますか?これらの更新のいずれもトリガーを一掃することができなかった場合、集約を更新せず、不正なデータにつながる可能性があります。
エリック

ラボ、手順、ワクチン、患者に関するすべての情報を1つのテーブルにまとめることを検討していますか?悪いアイデア。実行しているクエリのタイプに適している場合は、スタースキーマを使用できる場合があります。
マイケルグリーン

1
インデックス付きビューの作成を検討しましたか?これらは、コードとベンダーの間に論理層を配置するため、ベンダーが下のものを変更した場合にビューを更新できます。また、インデックス付きビューは事前に設定されており、優れた読み取りパフォーマンスを提供します。これを行う際のより大きな考慮事項の1つは、ベンダーのデータベーステーブルの書き込み操作にかかる負荷です。しかし、これはおそらく、トリガなどを使用するよりも解決策を維持するために、クリーンかつ容易になる
ミカNikkel

返信が遅くなってすみません、フィードバックをありがとう。@Erik-はい、更新を計画しています。実行する一連のチェックリストスクリプトを使用して、以前のすべての変更がまだ適切であることを確認します。すべてのトリガー。
jreed121

@MichaelGreen-スタースキーマを調べますが、1つのテーブルにすべてのデータを格納するのが悪い考えだと思うのはなぜですか?アプリケーション環境はVPN上で完全に隔離されており、とにかくネットワークの外部からはアクセスできません。テーブルに何か問題が発生しても、すべてを書き戻すことができるため、世界の終わりではありません。このテーブルは、ミッションクリティカルなデータには使用されません。または、少なくとも、データが保存される唯一の場所でも、主要な場所でもありません。
jreed121

回答:


8

正しく理解できたら

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

私はこのようにアプローチします:

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

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

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

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

更新

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

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

したがって、これは極端な場合です。サードパーティのデータ構造から内部データ構造への変換は、サードINSERT/UPDATE/DELETEパーティのテーブルで発生するトリガーで実行されます。難しいかもしれません。トリガーのコードは、両方のシステムの内部構造に依存します。変換が自明でない場合INSERT/UPDATE/DELETE、元の状態が遅延して失敗する可能性があります。トリガーにバグがある場合、元のトランザクションに障害が発生するまで影響する可能性があります。サードパーティシステムが変更されると、トリガーが破損し、サードパーティシステムのトランザクションが失敗する可能性があります。

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

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


バッチ転送ルートを使用する場合、非常に高いトランザクション数(1日あたり100K)で変更追跡(およびニーズに応じて変更データキャプチャ)が成功しました。独自のステージング/監査/差分テーブルを実装するよりも簡単で、アプリケーションコードの変更やトリガーなしで展開できます。
マイケルグリーン

トリガーであろうとCDCであろうと、実際にリアルタイムに近づける唯一の方法は、ストリーミングまたはキューイングです。キューベースは、待ち時間と費用対効果の良い妥協案です。キューをより高速に処理するメソッドに時間がかかります。作業の大部分をアプリケーションから非同期にして、ユーザートランザクションの負荷を減らします。これまで、私はAllscripts Sunrise EMRに対して、これを並列のforeach C#呼び出しでキューを処理するサービスで行ってきました。新しいデータが処理され、ウェアハウスで利用可能になるまでの一般的な遅延は30秒
Brad D

「リアルタイム」と言っても過言ではないかもしれませんが、ミリ秒や5秒にはあまり関心がありませんが、ワークフローを推進するためにスタッフが頼るクエリはたくさんあります。クライアントが何かを行った場合(手順、予防接種など)、短期間でそれを示す必要があります。変換は取るに足らないものであり、変換ではありません。ベンダーテーブルの変更はあまり頻繁に変更されないため、過度に心配する必要はありません。とにかく今やらなければなりませんが、多数のレポート/クエリよりも1つのトリガーを更新/再作成する方が簡単だと思いました/ SP。更新ごとにチェックを実行します。
jreed121

@ jreed121、レポートよりもトリガーを更新する方簡単だと思います。変更をキャプチャするために各ソーステーブルにトリガーがある可能性が高いため、複数のトリガーになる可能性があります。それでも、これらのすべての変更を1つの巨大な非正規化テーブルに書き込まないでください。適切に正規化されたテーブルのセットに書き込みます。レポートは、管理するこれらの正規化されたテーブルに基づいており、変更される可能性がある元のテーブルに依存しないようにする必要があります。
ウラジミールバラノフ

3

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

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

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

データウェアハウスのようなものに非正規化するときは、予測できないデータに対して多くの異なるタイプのクエリを作成できるようにする必要があるときです。それはそれ自身の欠点とオーバーヘッドを持っているので、適切な場所ではなく、適切なものとして使用すべきです。


3

私は過去にこのような非常によく似た状況で24時間365日の製造会社で働いていましたが、最終的にトランザクションレプリケーションを使用することにしました。可能ですあなたはパッチが加入者に変更するものは何でも押し出すことができるように複製するDDLを設定します。明らかに、すべてに長所と短所があり、それらを比較検討して、会社に最適なものに対して何をサポートできるかを判断する必要があります。

プラス面:

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

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

  1. 費用。別のライセンスとより多くのハードウェア(仮想、またはその他)。
  2. レプリケーション。適切にセットアップすればうまく機能しますが、その点に到達するのは面倒です。
  3. メンテナンス。構造に有害な変更(インデックスの削除など)を行うと、スナップショットが適用されたとき(パブリケーションが変更された後、または記事が変更されたとき)に戻ります。

2

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

トリガーには、回避すべき多くの問題があります。

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

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


1.トリガーは単純であるため、スローされたエラーは、存在しても最小限に抑えられます。2.トリガー自体は複数の行を処理しません(つまり、トリガーでテーブル内の1つの行を更新しても、他の場所で複数の行が更新されることはありません)。テーブル-これはあなたが意味するものですか?3.これで対処できませんNOCOUNTか?4.宛先テーブルにはトリガーがありません他のトリガーにも同じことを保証できます。
jreed121

あなたが言うように、トリガーを機能させることは理論的には可能です。それは実際には彼らが決してしないということです。
アンドマー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.