6

何百万もの行を含むSQL2005テーブルがあり、昼夜を問わずユーザーがヒットしています。このテーブルは、外部キー制約がある20個ほどの他のテーブルによって参照されます。私が定期的に行う必要があるのは、「アクティブ」フィールドがfalseに設定され、親レコードを参照する子テーブルに他のレコードがないこのテーブルからすべてのレコードを削除することです。一度に1つずつ削除して、制約に違反するSQLエラーを発生させる以外の方法でこれを行う最も効率的な方法は何ですか?また、制約を無効にするオプションはなく、かなりの時間、親テーブルをロックすることはできません。

4

3 に答える 3

7

リンクされていない非アクティブな行がリンクされる可能性が低い場合は、次を実行できます(または、外部キーメタデータに基づいて動的に構築することもできます)。

SELECT k.*
FROM k WITH(NOLOCK)
WHERE k.Active = 0
AND NOT EXISTS (SELECT * FROM f_1 WITH(NOLOCK) WHERE f_1.fk = k.pk)
AND NOT EXISTS (SELECT * FROM f_2 WITH(NOLOCK) WHERE f_2.fk = k.pk)
...
AND NOT EXISTS (SELECT * FROM f_n WITH(NOLOCK) WHERE f_n.fk = k.pk)

そして、それを非常に簡単にDELETEに変えることができます。ただし、大規模な削除では多くのロックが保持される可能性があるため、これをテーブルに入れてからバッチで削除することをお勧めします。レコードがリンクされない限り、バッチは失敗しません。

これを効率的に行うには、関連するテーブルのFK列にインデックスを付ける必要があります。

左結合を使用してこれを行うこともできますが、(場合によっては)DISTINCTまたはGROUP BYを使用して重複排除する必要があり、実行プランは通常はそれほど良くなく、コード生成に役立ちません。

SELECT k.*
FROM k WITH(NOLOCK)
LEFT JOIN f_1 WITH(NOLOCK) ON f_1.fk = k.pk
LEFT JOIN f_2 WITH(NOLOCK) ON f_2.fk = k.pk
...
LEFT JOIN f_n WITH(NOLOCK) ON f_n.fk = k.pk
WHERE k.Active = 0
    AND f_1.fk IS NULL
    AND f_2.fk IS NULL
    ...
    AND f_n.fk IS NULL
于 2010-05-06T23:53:47.010 に答える
4

名前の親テーブルがあり、任意のタイプの" Parent"フィールドとタイプの""フィールドがあります。また、彼自身の" "フィールドとテーブルの""フィールドへの参照である""フィールドを持つ2番目のテーブルがあります。次に、次のステートメントを使用できます。idActivebitChildidfkidParent

DELETE Parent
FROM Parent AS p LEFT OUTER JOIN Child AS c ON p.id=c.fk
WHERE c.id IS NULL AND p.Active=0
于 2010-05-07T00:18:40.913 に答える
0

あなたの質問について少し混乱しています。ただし、メインテーブルからLeftOuterJoinを実行することはできますが、外部キーがあるはずのテーブルに対してです。次に、Whereステートメントを使用して、接続テーブル内のnull値をチェックできます。

外部結合については、こちらを確認してください:http: //en.wikipedia.org/wiki/Join_%28SQL%29#Left_outer_join

また、レコードが削除されたときやfalseに設定されたときなどに、これらすべてを実行するためのトリガーを作成する必要があります。

于 2010-05-06T23:53:07.450 に答える