21

ライブ オブジェクトとドラフト オブジェクトの両方が必要であるというひねりを加えたオブジェクトのバージョン管理の実装を検討しています。潜在的に恐ろしいハックなしでそれが可能であるかどうか疑問に思っているので、これに関する誰かの経験からの洞察を使用できます。

例のためにタグ付きの投稿に分割しますが、私のユースケースはもう少し一般的です (ゆっくりと変化する次元を含む - http://en.wikipedia.org/wiki/Slowly_changeing_dimension )。

posts テーブル、tags テーブル、post2tag テーブルがあるとします。

posts (
 id
)

tags (
 id
)

post2tag (
 post_id fkey posts(id),
 tag_id fkey tags(id)
)

私はいくつかのことが必要です:

  1. 削除された行を含め、任意の日時に投稿がどのように見えるかを正確に示すことができます。
  2. 完全な監査証跡のために、誰が何を編集しているかを追跡します。
  3. 参照整合性を維持するために、具体化されたビュー (「ライブ」テーブル) のセットが必要です (つまり、ログは開発者に対して透過的である必要があります)。
  4. ライブおよび最新のドラフト行に対して適切に高速である必要があります。
  5. 下書き投稿とライブ投稿を共存させることができます。

さまざまなオプションを調査してきました。これまでのところ、私が思いついた最高のもの (ポイント #4/#5 を除く) は、SCD type6 ハイブリッド セットアップに少し似ていますが、現在のブール値を持つ代わりに、現在の行の具体化されたビューがあります。すべての意図と目的のために、次のようになります。

posts (
 id pkey,
 public,
 created_at,
 updated_at,
 updated_by
)

post_revs (
 id,
 rev pkey,
 public,
 created_at,
 created_by,
 deleted_at
)

tags (
 id pkey,
 public,
 created_at,
 updated_at,
 updated_by
)


tag_revs (
 id,
 public,
 rev pkey,
 created_at,
 created_by,
 deleted_at
)

post2tag (
 post_id fkey posts(id),
 tag_id fkey tags(id),
 public,
 created_at,
 updated_at,
 updated_by
)

post2tag_revs (
 post_id,
 tag_id,
 post_rev fkey post_revs(rev), -- the rev when the relation started
 tag_rev fkey tag_revs(rev), -- the rev when the relation started
 public,
 created_at,
 created_by,
 deleted_at,
 pkey (post_rev, tag_rev)
)

ピリオド (created_at、deleted_at) のインデックスを維持するために pg_temporal を使用しています。そして、トリガーを使用してさまざまなテーブルを同期させます。ヤダヤダヤダ... 下書きが公開されずにリビジョンに保存されるように、投稿/タグの編集をキャンセルできるトリガーを作成しました。それはうまくいきます。

post2tag の下書き行関連の関係について心配する必要がある場合を除きます。その場合、すべての地獄が解き放たれます。これは、何らかの設計上の問題があることを示唆しています。でもアイデアが尽きた…

データの重複を導入することを検討しました (つまり、ドラフト リビジョンごとに導入された n 個の post2tag 行)。この種の作品は、私が望むよりもずっと遅くなる傾向があります。

「最後のドラフト」にドラフトテーブルを導入することを検討しましたが、これはすぐに非常に見苦しくなります。

私はあらゆる種類のフラグを検討しました...

質問: 行バージョン制御環境でライブ行と非ライブ行を管理する一般的に受け入れられている方法はありますか? そうでない場合、何を試してかなりの成功を収めましたか?

4

5 に答える 5

11

アンカー モデリングは一時的な dB を実装するための優れた方法です。ウィキペディアの記事も参照してください。慣れるまで少し時間がかかりますが、うまく機能します。オンライン モデリング ツールがあり、提供された XML ファイルをロードすると、次の[File -> Load Model from Local File] ようなものが表示されるはずです[Layout --> Togle Names]

ここに画像の説明を入力

[Generate --> SQL Code]、テーブル、ビュー、およびポイント イン タイム関数の DDL を生成します。コードはかなり長いので、ここには掲載しません。コードを確認してください。DB 用に変更する必要がある場合があります。

モデリング ツールに読み込むファイルは次のとおりです。

<schema>
<knot mnemonic="EXP" descriptor="Expired" identity="smallint" dataRange="char(1)">
<identity generator="true"/>
<layout x="713.96" y="511.22" fixed="true"/>
</knot>
<anchor mnemonic="US" descriptor="User" identity="int">
<identity generator="true"/>
<attribute mnemonic="USN" descriptor="UserName" dataRange="varchar(32)">
<layout x="923.38" y="206.54" fixed="true"/>
</attribute>
<layout x="891.00" y="242.00" fixed="true"/>
</anchor>
<anchor mnemonic="PO" descriptor="Post" identity="int">
<identity generator="true"/>
<attribute mnemonic="TIT" descriptor="Title" dataRange="varchar(2)">
<layout x="828.00" y="562.00" fixed="true"/>
</attribute>
<layout x="855.00" y="471.00" fixed="true"/>
</anchor>
<anchor mnemonic="TG" descriptor="Tag" identity="int">
<identity generator="true"/>
<attribute mnemonic="TGT" descriptor="TagText" dataRange="varchar(32)">
<layout x="551.26" y="331.69" fixed="true"/>
</attribute>
<layout x="637.29" y="263.43" fixed="true"/>
</anchor>
<anchor mnemonic="BO" descriptor="Body" identity="int">
<identity generator="true"/>
<attribute mnemonic="BOT" descriptor="BodyText" dataRange="varchar(max)">
<layout x="1161.00" y="491.00" fixed="true"/>
</attribute>
<layout x="1052.00" y="465.00" fixed="true"/>
</anchor>
<tie timeRange="datetime">
<anchorRole role="IsTagged" type="PO" identifier="true"/>
<anchorRole role="IsAttached" type="TG" identifier="true"/>
<anchorRole role="BYAuthor" type="US" identifier="false"/>
<knotRole role="Until" type="EXP" identifier="false"/>
<layout x="722.00" y="397.00" fixed="true"/>
</tie>
<tie timeRange="datetime">
<anchorRole role="Contains" type="PO" identifier="true"/>
<anchorRole role="ContainedIn" type="BO" identifier="false"/>
<layout x="975.00" y="576.00" fixed="true"/>
</tie>
<tie>
<anchorRole role="CreatedBy" type="TG" identifier="true"/>
<anchorRole role="Author" type="US" identifier="false"/>
<layout x="755.10" y="195.17" fixed="true"/>
</tie>
<tie>
<anchorRole role="CreatedBy" type="PO" identifier="true"/>
<anchorRole role="Author" type="US" identifier="false"/>
<layout x="890.69" y="369.09" fixed="true"/>
</tie>
<tie>
<anchorRole role="ModifiedBy" type="BO" identifier="true"/>
<anchorRole role="Author" type="US" identifier="false"/>
<layout x="1061.81" y="322.34" fixed="true"/>
</tie>
</schema>
于 2011-06-12T15:23:31.893 に答える
2

SCD タイプ 2 と PostgreSQL ルールとトリガーを使用してテンポラル データベースを実装し、ActiveRecord の自己完結型パッケージにラップしました: http://github.com/ifad/chronomodel

ただし、設計は言語/フレームワークから独立しています。ルールとトリガーを手動で作成でき、残りはデータベースが処理します。https://github.com/ifad/chronomodel/blob/master/README.sqlをご覧ください。

また、幾何学的演算子を使用した時間データの効率的なインデックス作成とクエリもボーナスとして含まれています。:-)

于 2013-02-01T11:05:10.617 に答える
1

私はそれを釘付けにしたと思います。基本的に、関連するテーブルに (一意の) 下書きフィールドを追加し、下書きを新しい投稿/タグ/その他であるかのように操作します。

posts (
 id pkey,
 public,
 created_at stamptz,
 updated_at stamptz,
 updated_by int,
 draft int fkey posts (id) unique
)

post_revs (
 id,
 public,
 created_at,
 created_by,
 deleted_at,
 pkey (id, created_at)
)

tags (
 id pkey,
 public,
 created_at,
 updated_at,
 updated_by,
 draft fkey tags (id) unique
)


tag_revs (
 id,
 public,
 created_at,
 created_by,
 deleted_at,
 pkey (id, created_at)
)

post2tag (
 post_id fkey posts(id),
 tag_id fkey tags(id),
 public,
 created_at,
 updated_at,
 updated_by,
 pkey (post_id, tag_id)
)

post2tag_revs (
 post_id,
 tag_id,
 public,
 created_at,
 created_by,
 deleted_at,
 pkey (post_id, tag_id, created_at)
)
于 2011-06-12T14:54:23.750 に答える
1

post2tag_revs には、根本的に異なる 2 つの概念を表現しようとしているという問題があります。

ドラフト投稿リビジョンに適用されたタグは、そのリビジョンが公開されない限り、その 1 つのリビジョンにのみ適用されます。

タグが公開されると (つまり、公開された投稿のリビジョンに関連付けられると)、タグが取り消されるまで、投稿の将来のすべてのリビジョンに適用されます。

また、タグの追加や削除を関連付けることができるように、リビジョンを複製して人為的にこれを強制しない限り、公開されたリビジョンに関連付ける、または関連付けを解除することは、公開されているリビジョンと必ずしも同時ではありません...

post2tag_revs.post_rev を下書きタグにのみ関連させることで、モデルを変更します。リビジョンが公開されたら (そしてタグが有効になると)、タイム スタンプ列を使用して、公開された有効性の開始と終了をマークします。この変更を表す新しい post2tag_revs エントリが必要な場合とそうでない場合があります。

ご指摘のとおり、これによりこの関係はバイテンポラルになります。ブール値を post2tag に追加して、タグが現在投稿に関連付けられていることを示すことにより、「通常の」ケースでパフォーマンスを向上させることができます。

于 2011-06-11T21:00:29.657 に答える
0

posts、tags、post2tag の 3 つのテーブルのみを使用します。

start_time 列と end_time 列をすべてのテーブルに追加します。キー、start_time、および end_time の一意のインデックスを追加します。end_time が null のキーに一意のインデックスを追加します。トリガーを追加します。

現在の場合:

SELECT ... WHERE end_time IS NULL

当時の:

WHERE (SELECT CASE WHEN end_time IS NULL
THEN (start_time <= at_time)
ELSE (start_time <= at_time AND end_time > at_time)
END)

関数索引により、現在のデータの検索は遅くありません。

編集:

CREATE UNIQUE INDEX ... ON post2tag (post_id, tag_id) WHERE end_time IS NULL;
CREATE UNIQUE INDEX ... ON post2tag (post_id, tag_id, start_time, end_time);

FOREIGN KEY (post_id, start_time, end_time) REFERENCES posts (post_id, start_time, end_time) ON DELETE CASCADE ON UPDATE CASCADE;
FOREIGN KEY (tag_id, start_time, end_time) REFERENCES tags (tag_id, start_time, end_time) ON DELETE CASCADE ON UPDATE CASCADE;
于 2011-06-12T02:44:51.623 に答える