9

多くのデータベースと同様に、各テーブルで変更された行の以前のバージョンを記録するデータベースを設計しています。

この問題の標準的な解決策は、データ テーブルごとに履歴テーブルを保持することです。データ テーブルで行を更新する必要がある場合は常に、現在の行のコピーが履歴テーブルに挿入され、データ テーブルの行よりも優先されます。更新されます。

私にとってこのソリューションの欠点:

  • 1 つではなく 2 つのテーブルのメンテナンス (テーブルの構造を変更する必要がある場合)
  • アプリケーションは、一方ではなく両方のテーブルを認識する必要があります
  • テーブル名と履歴テーブル名の規則を維持するために、テーブルの名前を短くする必要がある場合があります (たとえば、SOME_TABLE、SOME_TABLE_HIST)。

私は別の解決策を検討していて、それが大丈夫かどうか知りたい. テーブルごとに、列 IS_LAST を追加します

  • 行がテーブルに挿入されると、IS_LAST=1 で挿入されます。
  • 行が更新されると、元の行のコピーが同じテーブルに複製され、IS_LAST=0 が変更され、元の行が必要に応じて更新されます (IS_LAST=1 のまま)。

私の場合、行は平均 10 回更新されると仮定します。また、アプリケーションによって実行されるアクションの少なくとも 90% は、行の最新バージョンでのみ発生すると想定します。

私のデータベースは Oracle 10g なので、「アクティブな」テーブルをスリムに保つために、テーブルを 2 つのパーティション (IS_LAST=1 パーティションと IS_LAST=0 パーティション) に分割できます。

パーティショニングは履歴データ保持の問題を解決する良い方法ですか?

このソリューションは、他のパーティションの可能性をこれらのテーブルに制限しますか?

ありがとう!

4

10 に答える 10

6

最初の質問は次のとおりです。そのデータをどうしますか?明確なビジネス要件がない場合は、それを行わないでください。

私は似たようなことをしました。3年間実行した後、「有効なデータ」の約20%があり、残りは「以前のバージョン」です。そしてそれは1000万+4000万レコードです。過去3年間に、変更の履歴を調査するための2つのリクエストがありましたが、どちらのリクエストもばかげていました。レコード変更のタイムスタンプを記録し、残業しているかどうかを確認するように求められました(午後5時以降)。

現在、誰も必要としないデータの80%を含む特大のデータベースで立ち往生しています。

編集:

あなたが可能な解決策を求めたので、私は私たちがしたことを説明します。検討しているソリューションとは少し異なります。

  1. すべてのテーブルには代理主キーがあります。
  2. すべての主キーは単一のシーケンスから生成されます。Oracleは数値を生成してキャッシュできるため、これは正常に機能します。したがって、ここではパフォーマンスの問題はありません。ORMを使用し、メモリ内の各オブジェクト(およびデータベース内の対応するレコード)に一意の識別子を持たせたいと考えました
  3. ORMを使用し、データベーステーブルとクラス間のマッピング情報は属性の形式になっています。

すべての変更は、次の列を持つ単一のアーカイブテーブルに記録されます。

  • id(代理主キー)
  • タイムスタンプ
  • 元のテーブル
  • 元のレコードのID
  • ユーザーID
  • トランザクションタイプ(挿入、更新、削除)
  • varchar2フィールドとしてデータを記録する
    • これは、フィールド名と値のペアの形式の実際のデータです。

物事はこのように機能します:

  • ORMには、コマンドの挿入/更新と削除があります。
  • 挿入/更新および削除コマンドをオーバーライドするすべてのビジネスオブジェクトに対して1つの基本クラスを作成しました
    • 挿入/更新/削除コマンドは、リフレクションを使用してフィールド名と値のペアの形式で文字列を作成します。コードはマッピング情報を検索し、フィールド名、関連する値、およびフィールドタイプを読み取ります。次に、JSONに似たものを作成します(いくつかの変更を追加しました)。オブジェクトの現在の状態を表す文字列が作成されると、アーカイブテーブルに挿入されます。
  • 新規または更新されたオブジェクトがデータベーステーブルに保存されると、そのオブジェクトはターゲットテーブルに保存されると同時に、現在の値を持つ1つのレコードがアーカイブテーブルに挿入されます。
  • オブジェクトが削除されると、ターゲットテーブルからオブジェクトが削除されると同時に、トランザクションタイプが「DELETE」である1つのレコードがアーカイブテーブルに挿入されます。

プロ:

  • データベース内のテーブルごとにアーカイブテーブルはありません。また、スキーマが変更されたときにアーカイブテーブルを更新することについて心配する必要はありません。
  • 完全なアーカイブは「現在のデータ」から分離されているため、アーカイブによってデータベースのパフォーマンスが低下することはありません。別のディスク上の別のテーブルスペースに配置すると、正常に動作します。
  • アーカイブを表示するための2つのフォームを作成しました。
    • アーカイブテーブルのフィルターに従ってアーカイブテーブルを一覧表示できる一般的なビューアー。フィルタデータユーザーはフォームに入力できます(期間、ユーザー、...)。各レコードはフィールド名/値の形式で表示され、各変更は色分けされています。ユーザーは、各レコードのすべてのバージョンを確認でき、誰がいつ変更を加えたかを確認できます。
    • 請求書ビューア-これは複雑でしたが、元の請求書入力フォームと非常によく似た請求書を表示するフォームを作成しましたが、異なる世代を表示できるいくつかの追加ボタンがあります。このフォームを作成するにはかなりの労力を要しました。フォームは数回使用されましたが、現在のワークフローでは必要なかったため、忘れられました。
  • アーカイブレコードを作成するためのコードは、単一のC#クラスにあります。データベース内のすべてのテーブルにトリガーを設定する必要はありません。
  • パフォーマンスはとても良いです。ピーク時には、システムは約700〜800人のユーザーによって使用されます。これはASP.Netアプリケーションです。ASP.NetとOracleの両方が、8GbRAMを備えた1つのデュアルXEONで実行されています。

短所:

  • 単一テーブルのアーカイブ形式は、データテーブルごとに1つのアーカイブテーブルがあるソリューションよりも読みにくいです。
  • アーカイブテーブルの非IDフィールドの検索は困難LIKEです。文字列に対しては、演算子のみを使用できます。

したがって、もう一度、アーカイブの要件を確認してください。これは簡単な作業ではありませんが、利益と使用は最小限に抑えることができます。

于 2009-04-03T22:06:02.790 に答える
2

2つのテーブルを作成します。1つはIsLastの種類の値用で、もう1つは履歴の値用です。次に、isLastが更新されるたびに履歴テーブルに値を挿入するトリガーを設定します。

于 2009-04-03T21:42:52.753 に答える
1

保持する履歴のテーブルが 1 つまたは 2 つある場合は、Tuinstoel が提案したとおりにそれを行います。しかし、これを行うテーブルが数十ある場合は、zendar で説明されているソリューションにさらに移行します。その理由はこれです。

などの質問にどう答えますか?

  • すべてが順調だった昨日から何が変わったのですか?

  • ユーザー SMITHG は変更を加えましたか?

これらの質問には、テーブルが個別の _hist テーブルであるか、テーブル内のパーティションであるかにかかわらず、テーブルごとに 1 つのクエリが必要です。とにかく、それはクエリの巨大なリストです。このように見える中央のテーブルがある場合、それはパイの一部です。

table_name, Column_name, PK, Before_value, After_value, User, timestamp

挿入には after 値しかありません。

削除には前の値しかありません。

更新には両方がありますが、変更された列に対してのみです。

いくつかのバリエーション

必要に応じて、I/U/D の列を含めることができます。挿入の列の値を除外し、PK と I のみを記録することができます。これは、正しい値がまだ表にあるためです。

これは Oracle であるため、table_name で分割できます。つまり、実際には、実際のテーブルごとに 1 つのヒスト「テーブル」があります。

上記の質問には簡単に答えることができます。これは、非常に単純に、最もよく聞かれる質問だと思います。また、パーティションまたは _hist テーブルを使用して回答できるすべての質問を処理します。

于 2009-04-04T14:28:08.500 に答える
0

私の頭に浮かぶ主な制限は、テーブルの大部分が履歴データになることです。これは、懸念事項にインデックスを付け、CRUDクエリにさらに複雑さをもたらす可能性があることを意味します。

この状況の通常の解決策と思われるものを使用したくない特別な理由はありますか?

于 2009-04-03T21:43:54.403 に答える
0

主キーをどのように定義しますか?同じテーブルの履歴行をキーピングするため、同じ主キーを持つ行が多数あります。

また、単一の「実際の」行が何度も変更されたときに、履歴行の順序を知る方法がないようです。

(私が取り組んだ1つのプロジェクトでは、コードスミスを使用してすべての履歴テーブルとトリガーを生成しました。これは非常にうまく機能しました。)

于 2009-04-03T21:51:12.920 に答える
0

IS_LAST=1パーティションとIS_LAST=0パーティションシステムを使用します。パーティション化されているため高速になり (パーティションのプルーニング)、通常のテーブルと履歴テーブルの和集合をクエリする必要はありません。

1/0 ではなく、IS_LAST='Y'/'N' を使用します。1 と 0 は無意味です。

IS_LAST='Y'エンティティごとに最大 1 つの行があることを保証するのに役立つ特別なトリックがありIS_LAST='N'ますIS_LAST='Y'。ここで説明されています: http://www.akadia.com/services/ora_function_based_index_1.html

于 2009-04-04T09:56:28.120 に答える
0

それはすべてあなたが持っているものに依存します:

  • Standard Edition と Enterprise Edition のどちらを実行していますか? パーティショニングは、Enterprise Edition のオプションとしてのみ含まれています。詳細については、こちらをご覧ください。
  • 独自のコードを維持する必要がない簡単なソリューションを探している場合は、 Workspace Managerを使用することを検討してください。ただし、私が見つけたいくつかの制限があります (たとえば、10gR2 でしか確認していませんが、Oracle Text インデックスのメンテナンスは、不可能ではないにしても難しいようです)。
  • それ以外の場合は、zvolkov のソリューション (履歴テーブルにトリガーを書き込むライブ テーブル) または Mark Brady のソリューション (変更ログ) のいずれかを使用します。私は両方のパターンを使用しましたが、それぞれに長所と短所があります。
  • @zendar: フラッシュバック クエリは、元に戻した時点までしか機能しません。これは長期的な解決策ではなく、せいぜい数時間 (指定した元に戻す保存期間によって異なります) を振り返る解決策にすぎません。
于 2009-04-10T03:12:00.607 に答える
0

追跡データを履歴テーブルに移動する手順を実行した場合、時間に基づいて追跡することで、毎日、および取引量が最も少ない時間に応じて、ビジネスの終わりまたは真夜中に探している効果を達成するのに役立ちますか?それが役立つだろう ??そうすれば、すべての更新が挿入され、ロックも不要になります。よろしく、アンディ

于 2009-04-06T04:21:23.480 に答える
0

他のものと同様に、カスタムの保存および削除メソッドを含むベース オブジェクトで ORM (Propel) を使用します。これらのメソッドは、ORM に付属する標準の保存と削除をオーバーライドします。どの列が変更されたかを確認し、変更された列ごとに変更テーブルに 1 行を作成します。

テーブルのスキーマchange: change_pk、user_fk、user_name、session_id、ip_address、method、table_name、row_fk、field_name、field_value、most_recent、date_time

例: 1, 4232, 'Gnarls Barkley', 'f2ff3f8822ff23', '234.432.324.694', 'UPDATE', 'User', 4232, 'first_name', 'Gnarles', 'Y', '2009-08-20 10 :10:10';

于 2009-08-20T07:17:48.413 に答える