現在プロジェクトに取り組んでおり、大多数のユーザー(ユーザーロール)に対してソフト削除を実装する必要があります。データベースの各テーブルに「is_deleted = '0'」フィールドを追加し、特定のユーザーロールが特定のレコードの削除ボタンを押した場合に「1」に設定することにしました。
今後のメンテナンスのために、各SELECTクエリには、is_deleted = '1'のレコードが含まれないようにする必要があります。
ソフト削除を実装するためのより良いソリューションはありますか?
更新:アプリケーションデータベース内のすべてのテーブル/フィールドに対する変更(フィールド、古い値、新しい値、時間、ユーザー、IP)を追跡する監査データベースがあることにも注意してください。
WHERE IS_DELETED='0'
句を含むビューに対してすべてのクエリを実行できます。
削除が行われた日時を含むdeleted_at
列に頼ります。次に、削除に関する無料のメタデータを少し取得します。 SELECT
の場合、行を取得するだけWHERE deleted_at IS NULL
is_deleted
列を持つことは、かなり良いアプローチです。 Oracleの場合は、パフォーマンスをさらに向上させるために、is_deleted
列にリストパーティションを作成してテーブルをパーティション分割することをお勧めします。次に、削除された行と削除されていない行は物理的に異なるパーティションにありますが、あなたにとっては透過的です。
その結果、次のようなクエリを入力すると
SELECT * FROM table_name WHERE is_deleted = 1
次に、Oracleは「パーティションのプルーニング」を実行し、適切なパーティションのみを調べます。内部的にはパーティションは別のテーブルですが、ユーザーとしては透過的です。パーティション化されているかどうかに関係なく、テーブル全体を選択できます。ただし、Oracleはクエリを実行できます必要なパーティションのみ。たとえば、is_deleted = 0
で1000行、is_deleted = 1
で100000行があり、is_deleted
でテーブルをパーティション分割するとします。条件を含めると
WHERE ... AND IS_DELETED=0
その後、Oracleは1000行のパーティションのみをスキャンします。テーブルがパーティション化されていない場合、101000行(両方のパーティション)をスキャンする必要があります。
残念ながら、最良の対応は、一時的な削除を使用して何を達成しようとしているか、これを実装しているデータベースによって異なります。
SQL Serverでの最善の解決策は、SMALLDATETIMEまたはDATETIMEのタイプ(必要な粒度に応じて)でdeleted_on/deleted_at列を使用し、その列をnullにできるようにすることです。 SQL Serverでは、行ヘッダーデータにテーブルの各列のNULLビットマスクが含まれているため、IS NULLまたはIS NOT列に格納されている値をチェックするよりもNULL。
大量のデータがある場合は、データベース自体または2つの個別のテーブル(ProductsやProductHistoryなど)またはインデックス付きビューのいずれかを使用して、データのパーティション分割を確認する必要があります。
Is_deleted、is_archiveなどのフラグフィールドは、1つの意味しか持たないため、通常は避けます。 nullableなdeleted_at、archived_atフィールドは、自分自身とアプリケーションを継承する誰にとっても追加のレベルの意味を提供します。また、ペストのようなビットマスクフィールドは、意味を理解するためにビットマスクがどのように構築されたかを理解する必要があるため、避けます。
テーブルが大きくパフォーマンスに問題がある場合は、「削除された」レコードをいつでも別のテーブルに移動できます。このテーブルには、削除時間、レコードを削除したユーザーなどの追加情報があります。
そうすれば、プライマリテーブルに別の列を追加する必要がなくなります。
これは、必要な情報とサポートするワークフローによって異なります。
次のことができるようにしますか?
レコードが削除されて4回削除されなかった場合、それが現在、削除されていない状態であることを知っていれば十分ですか、それとも途中で何が起こったかを知ることができますか(連続する間の編集を含む)削除!)?
一意性制約違反を引き起こすソフト削除されたレコードに注意してください。 DBに一意の制約のある列がある場合は、以前に一時削除されたレコードによってレコードの再作成が妨げられないように注意してください。
サイクルについて考えてみましょう:
2番目の作成では、login = JOEがすでにソフト削除された行にあるため、制約違反が発生します。
いくつかの手法:1.削除されたレコードを新しいテーブルに移動します。 2.ログインおよびdeleted_atタイムスタンプ列全体で一意性制約を作成します
私の意見は、新しいテーブルに移動するための+1です。すべてのクエリで* AND delete_at = NULL *を維持するには、多くの規律が必要です(すべての開発者向け)。
削除されたデータをジムが言ったように別のテーブルに移動すると、確実にパフォーマンスが向上します。また、いつ、なぜ、誰によって削除されたかの記録も得られます。
すべてのクエリにwhere
deleted
= 0 </ code>を追加すると、クエリの速度が大幅に低下し、テーブルにあるインデックスの使用が妨げられます。可能な限り、テーブルに「フラグ」を設定しないでください。
あなたはどの製品について言及していませんが、SQL Server 2008とpostgresql(およびその他の確信がある)では、フィルター処理されたインデックスを作成できるため、is_deleted = 0のカバリングインデックスを作成して、この特定のアプローチのいくつかの欠点を軽減できます。
プロジェクトで使用するものは、statusIndをビットマスクとして使用するstatusInd tinyint not null default 0列です。これにより、データ管理(削除、アーカイブ、複製、復元など)を実行できます。これをビューで使用して、使用するアプリケーションのデータの配布、公開などを行うことができます。ビューに関するパフォーマンスが問題になる場合は、小さなファクトテーブルを使用してこの情報をサポートし、ファクトを削除して、リレーションを削除し、いわゆる削除を許可します。
適切にスケーリングし、データ中心であり、データのフットプリントをかなり小さく保ちます-リアルタイムの懸念がある350GB以上のDBの鍵。代替手段、テーブル、トリガーを使用すると、必要に応じて機能する場合と機能しない場合があるオーバーヘッドがあります。
SOX関連の監査では、ケースを支援するためにフィールド以上のものが必要になる場合がありますが、これは役立つ場合があります。楽しい
is_deleted = 0をチェックするビュー、関数、またはプロシージャを使用します。つまり、後で他の理由でテーブルを変更する必要がある場合に備えて、テーブルを直接選択しないでください。
より大きなテーブルのis_deleted列にインデックスを付けます
すでに監査証跡があるため、削除日を追跡することは冗長です
私はステータス列を保持することを好むので、いくつかの異なる構成、つまり、公開、プライベート、削除、needsAproval ...に使用できます。
他のスキーマを作成し、すべてをデータスキーマに付与します。新しいスキーマにVPDを実装して、すべてのクエリに述語が追加され、削除されていない行のみを追加できるようにする述語を追加します。 http://download.Oracle.com/docs/cd/E11882_01/server.112/e16508/cmntopc.htm#CNCPT62345
@AdditionalCriteria( "this.status <> 'deleted'")
これを@entityの上に置きます