5

この質問を見たことに最初に注意してください:内部結合を使用した TSQL の削除

大きなテーブルといくつかの外部キー関係があり、それぞれに特定の年齢のデータがあります。DB が無限に大きくなるのを防ぐために、特定のデータよりも古いデータを定期的に削除する必要があります。

指定されたパラメーターによって必要に応じて星の各ポイントから削除するクエリを作成しています (残念ながら、これらは構成可能であり、テーブル間で異なります)。

この最初の削除の後、中央のテーブルがあり、データベースを削除すると条件がチェックされるため、削除しようとする作業の 2 倍の作業を行っているのではないかと心配しています。私は次のセットを持っています:

AND NOT EXISTS
(SELECT key 
FROM table 
WHERE table.key = centretable.key)

これは、TSQL が適切なアンチ セミ ジョインを作成し、インデックスに対して適切に実行していることを示しています。問題は、削除するもののリストを作成し、削除を実行するときに同じチェックを再度行うことです。

私の質問は、行単位での削除の試行があるかどうかということだと思います (カーソルでそれを行うのは、それがどれほど遅いかを知っているので行いません) が、そのようなキーワードが存在すると思うでしょう。しかし、それを見つけることができたのは幸運でした。

4

6 に答える 6

2

リレーションシップを 1 回だけチェックする単一のコマンドに関しては (この例では 2 回ではなく、 の場合はNOT EXISTS1 回DELETE

(壁のアイデアから外れて):これが大きな問題である場合は、トリガーを使用してカウンターを更新する、ある種の参照カウントの実装を試すことができます-しかし、実際には、これは単にあなたがすでに持っているようなキー。

削除中に調査することもできNOCHECKます (自分で確認しているため)。ただし、これはテーブル レベルでのみ実行できます (管理スクリプトではおそらく問題ありませんが、運用コードでは問題ありません)。つまり、次のようになります。

-- disable
alter table ChildTableName nocheck constraint ForeignKeyName

-- enable
alter table ChildTableName check constraint ForeignKeyName

簡単なテストでは、これを有効にすると、外部キーに対して追加のクラスター化インデックス スキャンが実行されることがわかります。無効にすると、これは省略されます。

完全な例を次に示します。2 つの操作のクエリ プランを確認できますDELETE... (理想的には、残りのコードから分離して):

create table parent (id int  primary key)
create table child (id int  primary key, pid int)
alter table child add constraint fk_parent foreign key (pid)
    references parent (id)

insert parent values (1)
insert parent values (2)
insert child values (1,1)
insert child values (2,1)

-- ******************* THIS ONE CHECKS THE FOREIGN KEY
delete from parent
where not exists (select 1 from child where pid = parent.id)

-- reset
delete from child
delete from parent
insert parent values (1)
insert parent values (2)
insert child values (1,1)
insert child values (2,1)

-- re-run with check disabled
alter table child nocheck constraint fk_parent

-- ******************* THIS ONE DOESN'T CHECK THE FOREIGN KEY    
delete from parent
where not exists (select 1 from child where pid = parent.id)

-- re-enable
alter table child check constraint fk_parent

繰り返しますが、これは管理スクリプトなどからのみ実行する必要があることを強調します。

于 2009-07-06T07:24:59.187 に答える
1

選択した文のインデックス付きビューを作成できます。

SELECT key FROM table WHERE table.key = centretable.key

インデックス付きビューはデータの物理コピーであるため、非常に高速にチェックできます。

ビューを更新するオーバーヘッドがあるため、使用パターンに対してこれをテストする必要があります。

于 2009-07-06T09:04:23.510 に答える
0

あなたの質問に対する簡単な答えはノーです。マスターレコードへのすべての外部キー参照がなくなったときにマスターレコードを削除するための標準の RDBMS キーワードはありません (もちろん、複数のテーブルの外部キーを説明するものはありません)。

最も効率的なオプションは、外部キーを持つ各テーブルの一連の NOT EXISTS() 句に基づいて「中心」から削除するために必要に応じて実行される 2 番目のクエリです。

これは、あなたの状況にどちらも当てはまると私が信じている2つのステートメントに基づいています。

  1. 「中心」(親) レコードよりも多くの「関連」レコードを削除します。したがって、他のテーブルのいずれかから削除するたびに「中心」を調整しようとする操作は、「中心」への瞬時の更新をもたらしますが、「中心」レコードをたまにだけ削除するために多くの無駄なクエリが必要になります。

  2. 「中心」から星に複数のポイントがあることを考えると、そのうちの 1 つで外部キーをチェックする「無駄な労力」は、全体に比べて最小限です。たとえば、「中心」から削除する前にチェックする外部キーが 4 つある場合、せいぜい 25% の時間しか節約できません。

于 2009-07-06T08:25:16.710 に答える
0

削除するものの同じリストを再利用している場合は、削除するキーを一時テーブルに挿入してから、2 番目のクエリでこれを使用することを検討できます。

SELECT Key, ...
INTO #ToDelete
FROM Table T
WHERE ...

次に、このようなもの

...
LEFT OUTER JOIN #ToDelete D
ON T.Key=D.Key
WHERE D.Key IS NULL

DROP #ToDelete
于 2009-06-29T08:09:32.927 に答える
0

削除での外部結合の使用について説明している記事を 1 つ見つけました: http://www.bennadel.com/blog/939-Using-A-SQL-JOIN-In-A-SQL-DELETE-Statement-Thanks-Pinal -デイブ-.htm

これがうまくいくことを願っています!

于 2009-07-06T07:34:42.460 に答える
0

データベースにテーブルを作成するときに外部キーを制約として指定した場合、削除ルールを設定することにより、削除の場合に何をすべきかをデータベースに伝えることができます。このルールは、ユーザーが外部キー関係に関係するデータを含む行を削除しようとした場合にどうなるかを指定します。「アクションなし」設定は、削除が許可されず、DELETE がロールバックされることをユーザーに通知します。そのように実装すると、削除する前に自分でチェックすることができなくなり、ある種の試みと見なされる可能性があります。少なくとも、MS SQL ではそのように機能します。http://msdn.microsoft.com/en-us/library/ms177288.aspx

于 2009-06-29T08:15:45.083 に答える