分别有两个查询,需要更新第一个查询中不在第二个查询中记录的某个字段。我用一个类似的sql例子说明查询1: select a.name,b.value from a,b where a.keyid=b.keyid
查询2: select c.name,d.value from c,d where c.keyid=d.keyid两者minus的结果中的记录对应的b表的字段time需要更新。b和d数据量在接近千万,a和c数据量在百万量级。本来想用minus,因为听说数据量大的时候,虽然minus会sort,但是据说比表联合查询快。但是不知道使用minus怎么写这个update语句。
我用的方法是用exists,但是速度实在是大家帮我想想该怎么提高这个速度update b set b.time=sysdate-1
where not exists
(select 1 from a,c,d where c.keyid=d.keyid and 
                           a.keyid=b.keyid and 
                           a.name=c.name  and 
                           b.value=d.value
);这个已经是最优的方法了吗?

解决方案 »

  1.   

    已经建立过索引了。我换了表的顺序,看执行计划并没有什么变化。
    这个任务可以使用minus完成吗?
      

  2.   

    可以,但是使用minus的效率更慢
      

  3.   

    自己解决了这个问题。因为a,b,c,d四个表一起关联更新效率很低。他们四个表都有一个共同的节点字段,例如在abcd四个表中都有一部分数据属于节点A。而ab表的节点A的数据与cd表不是节点A的数据是没有关联的。
    所以将节点名字先用cursor提取出来,在循环处理,循环体中的sql语句还是上面的,只不过多了对每个表的节点字段内容的限制。
    现在的速度就快多了。结论:一个大的sql有时候不如循环执行的小的sql速度快。
      

  4.   

    楼上的结论不对,你这种完全没必要用存储过程处理,速度肯定还是不理想的
    你可以先建个临时表
    create table temp as
    select b.keyid,b.value from a,b,c,d where c.keyid=d.keyid and 
                               a.keyid=b.keyid and 
                               a.name=c.name  and 
                               b.value=d.value
    然后对这个临时表两个列建复合索引
    然后更新
    update b set b.time=sysdate-1
    where not exists
    (select 1 from temp t where b.keyid=t.keyid and b.value=t.value);
      

  5.   

    我没有说清楚我的解决方法。但是我的解决方法应该不慢。
    我的方法用上后,原来要1个小时的问题,现在在3分钟解决。实际中的语句比这个要复杂的多,不单只是abcd四个表,也不是只有keyid,name来匹配就够了,实际中的匹配条件很多,所以我最早说的方法很慢。楼上的这个做法我再试一下,但是怀疑给临时表插入数据的那个select语句会执行很久,至少超过7分钟吧,如果算上所有的表,在这个查询中会有两张千万量级的表,两张百万量级,还有几个几千条的小表,也不会快的。我的方法是这样的,我还是用存储过程,然后使用了minus的方法,因为用节点来限制了minus前后的记录条数,所以minus很快。(minus的前后查询出来的结果都不超过10000条)。在循环体中用游标取一个个节点名字代入这个minus中求差。然后基于差值的结果做update,
    单次循环控制在了600ms以下。所以最后七分钟以内就处理完成了。我实践中这样确实至少比我最早的全部一起的那种 not exists的方法快。在同样的一个目的,但是不是abcd中只有两个大表的一个任务中,我就直接使用了上面的not exists的方法,验证发现这种情况下not exists比这种分节点的方式要快,我的例子中大概耗用时间分别是8秒和20秒。还有一个问题想讨论楼上的这种方法,你查询出来要插入临时表的数据在我的例子中会达到千万级别,这样一个插入很慢,因为涉及到redo之类的东西,但是在我的方法中,每个循环内部我都可以commit,也节省了这个消耗。我的经验是这样感觉的,不知道是不是这个原因