2017-10-19 3 views
0

これはthis questionに似ていますが、基本的には参照カウントの動作が必要です。逆方向の外部キーカスケード(またはデータベースガベージの収集方法)

複数のテーブル(Foo、Bar、Baz)があり、そこに格納されているものはすべて0以上の別のもの(Blah)を参照しています。私たちは時には新しいBlahを作ってFoo、Bar、Bazに添付します。しかし、既存のBlahを編集することはありません。現在、データベース内のすべてのFoos、Bars、Bazesを掃引し、使用されているBlahをマークし、マークされていないBlahをすべて削除するバッチ処理がありますが、これはかなりコストがかかるので、それは理想的にはデータベースそのものを介してオンラインで提供されます。トリガーベースのアプローチを研究することはできますが、むしろそれらを最後の手段として扱います。具体的に

this SQLFiddleのスキーマとデータを参照:

  • 私は新しいバー「some_bar」を挿入し、それがPK「R」、だけ既に孤立何とかして新しいブラブラで指している場合'x'は削除する必要があります。
  • 'a_foo'を削除した場合、削除されるのはBlahs 'a'と 'x'だけです - 特に 'b'と 'c'を入れておく必要があります
  • 'another_foo' 、blahs 'x'と 'y'を削除する必要があります
  • 'a_bar'を削除すると、Blah 'x'のみ削除することができます - 特にBlah 'c'は残る必要があります
  • 'another_bar blah 'q'を守る必要がある
  • 'a_baz'を削除すると、すべてのBlah 'p'、 'x'、 'z'が削除されている必要があります削除済み
  • 「another_baz」を削除すると、「blah 'x」だけが削除されます削除されました - Blahs 'b'と 'q'は周りに残る必要があります

私はこの仕事のためにトリガーまたは既存のマークスイープバッチ処理をしていますか、それとももっと良い方法がありますか?限りBLAHS.PKにカンマが含まれていることはできませんとして仕事をする次のクエリ以来のマークとスイープバッチ処理の必要はありません

答えて

1

:あなたがいずれかを定義することはできませんので、

delete from blahs 
where not exists (select 1 from foo where ','||some_blahs||',' like '%,'||blahs.pk||',%') 
    and not exists (select 1 from bar where bar.blah = blahs.pk) 
    and not exists (select 1 from baz where blahs.pk in (baz.a_blah, baz.another_blah)); 

あなたのテーブルFOOは面倒です参照整合性、またはそれに有用なインデックスをBARBAZとすることができます。代わりに次に

create table foo_blahs (foo_pk varchar2(20) references foo on delete cascade 
         , blah_pk varchar2(20) references blahs 
         , constraint foo_blah_pk primary key (foo_pk, blah_pk) enable); 

insert into foo (pk, some_blahs) values ('a_foo', 'a,b,c'); 

あなたが使用します。

insert into foo (pk) values ('a_foo'); 
insert into foo_blahs (foo_pk, blah_pk) values ('a_foo', 'a'); 
insert into foo_blahs (foo_pk, blah_pk) values ('a_foo', 'b'); 
insert into foo_blahs (foo_pk, blah_pk) values ('a_foo', 'c'); 

より良いDB設計は、多くの関係テーブルに多くとFOO.SOME_BLAHSを交換するかもしれません削除クエリは次のようになります。

delete from blahs 
where not exists (select 1 from foo_blahs where foo_blahs.blah_pk = blahs.pk) 
    and not exists (select 1 from bar where bar.blah = blahs.pk) 
    and not exists (select 1 from baz where blahs.pk in (baz.a_blah, baz.another_blah)); 
+0

ええ、 'foo'の「外部キー」設定は私の考えではありませんでしたが、フラットファイルの土地で設計されたデータを扱うためには何をしなければなりません...私自身は多対多のテーブルを持っていますが、それは他の場所で特別なケーシングの問題を生み出します。 – LThode

+0

ああ、あなたは何をしなければならないのですか?多対多の表現が可能な場合は、errloggingテーブルをblahsに追加することができます。 'EXECUTE DBMS_ERRLOG.CREATE_ERROR_LOG( 'blahs'、 'errlog');'その後、 doh ')reject limit unlimited; '参照整合性は、参照されたblahsが削除されないようにします。 errlogテーブルをグローバルな一時テーブルにすると、定期的にそれを掃除することについて心配する必要はありません。 – Sentinel

+0

最初のクエリについては、基本構造は機能しましたが、WHERE句は偽陽性の巨大な生成元であることが判明しました。私はそれをINSTRのアプリケーションに置き換えました。私はそれがLIKEのようにパフォーマンスが良いとは思わないが、少なくとも適切なレコードセットを返します。 – LThode

関連する問題