web-dev-qa-db-ja.com

IsDeleted(ソフト削除)の実装を余儀なくされた場合の適切なインデックスアーキテクチャは何ですか?

現在、完全に機能する既存のデータベースとアプリケーションがあります。現時点では、アーキテクチャを変更することはできません。現在、データベースの各テーブルには、デフォルトで「0」の「IsDeleted」NOT NULL BITフィールドがあります。アプリケーションがデータを「削除」すると、IsDeletedフラグが1に更新されます。

私が理解できないのは、各テーブルのインデックスをどのように構成するかです。現在、すべてのquery/join/etcは常にIsDeletedチェックを実装しています。これは、開発者が従わなければならない標準です。そうは言っても、各テーブルのすべてのクラスター化された主キーインデックスを変更して、主キーとIsDeleted BITフィールドを含める必要があるかどうかを判断しようとしています。また、毎回クエリ/結合/など。 IsDeletedチェックを実装する必要があります。これは、すべての単一インデックス(非クラスター化)にも、インデックスの最初のフィールドとしてIsDeletedフィールドを含める必要があるという適切な想定ですか?

もう1つの質問は、フィルター選択されたインデックスに関するものです。 "WHERE IsDeleted = 0"などのインデックスにフィルターを適用して、インデックスのサイズを小さくできることを理解しています。ただし、すべての結合/クエリはIsDeletedチェックを実装する必要があるため、(IsDeleted列が結合/クエリで使用されているため)フィルターされたインデックスが使用されないようにしますか?

IsDeletedアプローチを変更することはできません。

17
Jerad Skinner

ここで最も簡単な方法は、キーとクラスター化インデックスをそのままにして、フィルター処理されたインデックスを非クラスター化インデックスに使用することです。

さらに、いくつかの大きなテーブルをパーティション化されたヒープまたはパーティション化されたクラスター化列ストア(SQL Server 2016以降)に移行して、主キーと一意のインデックスをパーティション化しないでおくことができます。これにより、IsDeleted行の非キー列を別のデータ構造にプッシュできます。さらに、別の方法で圧縮したり、別のファイルグループに保存したりできます。

また、開発者がIsDeleted行をフィルターで除外するために、パラメーターではなくリテラルを使用していることを確認してください。パラメータを使用する場合、SQL Serverは両方のケースで同じクエリプランを使用する必要があります。

例えば

SELECT ... WHERE ... AND IsDeleted=0

そしてない:

SELECT ... WHERE ... AND IsDeleted=@IsDeleted

パラメーターを使用すると、フィルターされたインデックスの使用が妨げられ、パラメーターのスニッフィングで問題が発生する可能性があります。

これはあまり人気のない意見かもしれませんが、「どこでもこれを実行する」というものはないと思います。1つのサイズですべての質問に答えることはできます。

理由もなく大量のIsDeleted行をスキャンしているクエリがある場合、1つの解決策は、そのクエリを満たすためにフィルター処理された非クラスター化インデックスを作成することです。

別のオプションは、削除されていない行だけにフィルタリングされる、いくつかの異なるクエリで活用できるインデックス付きビューを作成することです。これは、NOEXPANDヒントを提供せずにインデックス付きビューの自動マッチングが機能するEnterprise Editionで特に役立ちます。

小さなテーブル、または頻繁に読み込まれるテーブルの場合、フィルター処理された非クラスター化インデックスまたはビューなどを追加すると、データベースに不要なオーバーヘッドが追加されるだけです。

9
Josh Darnell

削除はまれであるという合理的な仮定の下では、インデックスの変更は適切な解決策ではありません。

遅かれ早かれ、削除された行への参照を照会する必要があり、インデックスに含まれている行が突然非常に価値があることがわかりました。

ビューを使用している場合を除き、すべてのクエリを編集してフィルターを含める必要があることに注意してください。

2
Joshua

クエリを変更する権利と能力があることを願っています。

ただし、すべての結合/クエリはIsDeletedチェックを実装する必要があるため、(IsDeleted列が結合/クエリで使用されているため)フィルターされたインデックスが使用されないようにしますか?

一つ重要な点を申し上げたいと思います。

Transaction tableテーブルとMasterテーブルの両方が使用される複雑なクエリ。

TransactionテーブルでのみIsDeleted=0を使用します。 Masterテーブルでは使用しないでください。

例、

Select * from dbo.Order O
inner join dbo.category C on o.categoryid=o.categoryid
inner join dbo.Product P on P.Productid=o.Productid
where o.isdeleted=0

c.isdeleted=0Categoryテーブルで使用)には意味がありません。これは不要です。

同様にP.isdeleted=0を使用することに意味がありますか?

私はすべての削除されていない注文とその詳細が欲しいので。

ProductOrderである場合、またはActiveが参照されている場合に、Productidを削除するにはどうすればよいですか。

したがって、この方法で重要なクエリを注意深くデバッグすると、isdeleted = 0の一部を削除できる場合があります。

フィルタインデックスを盲目的に作成しないでください。最初に、非常に重要で時間がかかるクエリをすべて選択してください。

これらの遅いクエリを最適化し、フィルターされたインデックスについてのみ決定するか、インデックスを調整します。

0
KumarHarsh

IS_DELETEDフラグが0またはPKの値であるシステムを見ました。他のシステムでは、それはPKのネガティブでした。

ほとんどのクエリは「自然」またはビジネス(場合によってはマルチフィールド)キーによって値を取得するため、結合を除いてPKによってクエリされることはありません。ただし、メインテーブルと結合されたテーブルの最後に常にAND IS_DELETED = 0を追加しました。

このシステムには、変更を追跡するトランザクションテーブルごとに監査テーブルもありました。アプリケーションには、削除されたデータを含むすべてのデータ変更を表示する機能がありました。

0
Rick Ryker