优化我的(简单)SQL查询(连接)

时间:2012-08-08 13:36:51

标签: sql join firebird

我的查询似乎需要花费太长时间才能执行。自从我做了很多非常简单的选择/更新和v.simple连接之后,已经有一段时间了(几年),所以我在这里不仅仅是生锈了!

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
    );

内部选择似乎工作正常,如果缓慢(几秒钟),但只要我添加外部'计数不在'我最终不得不杀死我的数据库连接 - 所以没有好工作到应用程序! ;)

我希望上面的查询清楚我想要实现的目标...获取所有rawread标记,其中该标记与checkpoints / guards / incidentitems中的相应列不匹配。

我正在使用Flamebird数据库服务器(没有选择)和FlameRobin来运行查询,如果这很重要。

在某些时候,我还需要向外部选择添加一个查询,以确保我不选择tagcode为null或“”的任何rawreads。

我已经从out选项中删除了一个“char_length(tagcode)> 0”标准,以期加快速度,但我认为我的问题比这更基本。

5 个答案:

答案 0 :(得分:3)

许多数据库(也可能是Firebird)无法轻松优化NOT IN条件。因此,您可能会尝试将其重写为NOT EXTISTS。

另外看一下内部选择,我认为你加入那里的方式是产生太多行。它不是真正的连接,也不是笛卡尔产品。无论如何,我可以想象在那里做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)上的索引应该运行得相当快。

答案 1 :(得分:2)

NOT IN中的每个行都会调用RAWREADS内的

子查询,因此此查询运行缓慢。如果您作为过程运行,则将子查询结果转储到临时表中,并使用该临时表执行内部联接,并对TAGCODE执行负面条件

答案 2 :(得分: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 server

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
    );

答案 3 :(得分: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

答案 4 :(得分: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上有索引,那么查询在TABLEA中检索TABLEB中没有对应项的所有记录的确非常快