1

実行に時間がかかりすぎると思われるクエリがあります。非常に単純な select/update と v.simple join 以外のことをしてからしばらく (何年も) 経ちました。

SELECT count(distinct r.TAGCODE)
FROM RAWREADS r
where r.TAGCODE NOT IN (
    select distinct r.TAGCODE 
    from RAWREADS r, checkpoints c, guards g, INCIDENTITEMS i
        where r.TAGCODE = c.TAGNO
        or    r.TAGCODE = g.IDTAG
        or    r.TAGCODE = i.IDTAG
    );

内側の選択は、ゆっくりと (数秒) は正しく機能しているように見えますが、外側の 'count where not in' を追加するとすぐに、DB 接続を強制終了する必要があります。アプリケーションでの作業には適していません! ;)

上記のクエリが私が達成しようとしていることを明確にしていることを願っています...そのタグがcheckpoints/guards/incidentitemsのそれぞれの列と一致しないすべてのrawreadタグをフェッチします。

問題があれば、Flamebird データベース サーバー (選択の余地なし) と FlameRobin を使用してクエリを実行しています。

ある時点で、外側の選択にクエリを追加して、タグコードが null または "" である rawreads を選択しないようにする必要もあります。

スピードアップを期待して out select から "char_length(tagcode) > 0" 基準を削除しましたが、私の問題はそれよりも根本的なものだと思います。

4

5 に答える 5

3

多くのデータベース (おそらく Firebird も同様) は、NOT IN 条件を簡単に最適化できません。したがって、これを NOT EXISTS として書き直そうとするかもしれません。

さらに、内側の選択を見ると、そこに参加している方法があまりにも多くの行を生成していると思います。これは実際の結合ではありませんが、デカルト積でもありません。とにかく、そこでUNIONを実行する方が効率的であると想像できます。

だからこれを試してください:

SELECT count(distinct r.TAGCODE)
FROM RAWREADS r
where NOT EXISTS (
    select 1
    from checkpoints c
    where c.tagno = r.tagcode
    union all
    select 1 
    from guards g
    where g.idtag = r.tagcode
    union all 
    select 1 
    from INCIDENTITEMS i
    where i.idtag = r.tagcode);

にインデックスがあればcheckpoints(tagno)、かなり速く実行されるはずですguards(idtag)incidentitems(idtag)

于 2012-08-08T13:45:43.933 に答える
2

内部のサブクエリNOT INが各行に対して呼び出されるためRAWREADS、このクエリの実行が遅くなります。プロシージャとして実行している場合は、サブクエリの結果を一時テーブルにダンプし、その一時テーブルで内部結合を行い、負の条件を実行しますTAGCODE

于 2012-08-08T13:42:16.210 に答える
1
SELECT count(distinct r.TAGCODE)
FROM RAWREADS r
where NOT EXISTS (
    select *  
    from  checkpoints c, guards g, INCIDENTITEMS i
        where r.TAGCODE = c.TAGNO
        or    r.TAGCODE = g.IDTAG
        or    r.TAGCODE = i.IDTAG
    );

SQLサーバーの場合

SELECT count(distinct r.TAGCODE)
FROM RAWREADS r
where NOT EXISTS (
    select TOp 1 1   
    from  checkpoints c, guards g, INCIDENTITEMS i
        where r.TAGCODE = c.TAGNO
        or    r.TAGCODE = g.IDTAG
        or    r.TAGCODE = i.IDTAG
    );
于 2012-08-08T13:42:19.977 に答える
0

以下のコードは Firebird 2.5 と互換性があり、高速です。今はテストできませんが、それがアイデアです。CTR を使用して、サブクエリ コードを簡素化します。

with SQ1 as (
  select distinct r.TAGCODE as TAGCODE
  from RAWREADS r, checkpoints c, guards g, INCIDENTITEMS i
      where r.TAGCODE = c.TAGNO
      or    r.TAGCODE = g.IDTAG
      or    r.TAGCODE = i.IDTAG
)

SELECT count(distinct r.TAGCODE)
FROM RAWREADS r
left join SQ1 on (r.TAGCODE = SQ1.TAGCODE)
where SQ1.TAGCODE is NULL
于 2012-08-08T14:30:45.567 に答える
0

ほとんどすべての RDBMS で、最適化された NOT IN 句を取得する最善の方法は、次のように、WHERE 句で失敗条件を指定して LEFT OUTER JOIN を記述することです。

SELECT count(distinct r.TAGCODE)
FROM RAWREADS r
left outer join checkpoints c on r.TAGCODE = c.TAGNO
left outer join guards g on r.TAGCODE = g.IDTAG
left outer join INCIDENTITEMS i on r.TAGCODE=i.IDTAG
where 
  c.TAGNO is null AND
  g.IDTAG is null AND
  i.IDTAG is null

一般的な観点からは、NOT IN 句は次のようになります。

select * from TABLEA 
where TABLEA.ID NOT IN (SELECT ID from TABLEB)

で正常に変換できます

select TABLEA.*
from TABLEA 
left outer join TABLEB ON TABLEA.ID=TABLEB.ID
where TABLEB.ID is null

TABLEB が列 ID にインデックスを持っている場合、クエリは、TABLEB に対応するものがない TABLEA からすべてのレコードを取得する際に非常に高速です。

于 2012-08-09T10:09:33.763 に答える