我的问题:

DATEDIFF不走索引 merge into 不走索引_sql

DATEDIFF不走索引 merge into 不走索引_DATEDIFF不走索引_02

你们看我这个,1号的就走索引,4号的不走索引要全表,我希望4号走索引,加了强制走索引的语句也不管用,怎办?

(我的语句:)

update  t_mt  partition(P_MT5_1) mt set (mt.stat,mt.rpttime)=(select stat,rpttime from t_statbuf buf 
 where sj>=to_date('2013-05-04 00:00:00','yyyy-mm-dd hh24:mi:ss') and sj<to_date('2013-05-05 00:00:00','yyyy-mm-dd hh24:mi:ss') 
 and buf.msgid=mt.msgid
)
where  mt.ctime>=to_date('2013-05-04 00:00:00','yyyy-mm-dd hh24:mi:ss') and mt.ctime<to_date('2013-05-05 00:00:00','yyyy-mm-dd hh24:mi:ss') 
and mt.ourgetstatus='0' and mt.stat='0' --and mt.ret='0' 
and exists(select 1 from t_statbuf buf where sj>=to_date('2013-05-04 00:00:00','yyyy-mm-dd hh24:mi:ss') and sj<to_date('2013-05-05 00:00:00','yyyy-mm-dd hh24:mi:ss') 
    and  buf.msgid=mt.msgid) ;



大神(名次)说:


这个你最好用merge into 的方式。

这个两个表做关联再去做更新的,而update 这个你要做两次查询也,而且多字段更新效果比较差

修改后的sql:


merge into t_mt  partition(P_MT5_1) mt  
using (select * 
            from  t_statbuf 
            where sj>=to_date('2013-05-05','yyyy-mm-dd') 
            and sj<to_date('2013-05-06','yyyy-mm-dd') )  buf 
on(buf.msgid=mt.msgid)
when matched then
update set mt.stat=buf.stat,mt.rpttime=buf.rpttime
where  mt.ctime>=to_date('2013-05-05','yyyy-mm-dd') 
and mt.ctime<to_date('2013-05-06','yyyy-mm-dd') 
and mt.ourgetstatus='0' 
and mt.stat='0' --and mt.ret='0' 
;



结果:


我用的自己上面那个sql更新了20多分钟还没有结果,下面这个(怎么这么快!!~!):


66334 行,

DATEDIFF不走索引 merge into 不走索引_sql_03

121777 行,

DATEDIFF不走索引 merge into 不走索引_数据_04


然后继续问:


merge into 能删数据吗?那些被改过的数据,另一个表是要删掉的 ,用我原来的语句删,还是全表


答:


merge into 删除要看oracle版本的,版本高的是可以的


如果中途报错:

DATEDIFF不走索引 merge into 不走索引_sql_05




这个是你更新的表记录不唯一导致的



我自己写的:

1.更新mt中有状态的,mx没取的到mx,从4-27号开始,大概更新200万行,预计时间30分钟:

merge into t_busi_presend_mx  mx
using (select * 
from  t_mt 
where ctime>=to_date('2013-04-27','yyyy-mm-dd') 
)  mt 
on(=mt.mcid)
when matched then
update set mx.sjsendstatus=mt.stat,mx.rpttime=mt.rpttime
where  mx.cjsj>=to_date('2013-04-27','yyyy-mm-dd') 
and mx.sjsendstatus='NONE'



2.删除buf(204万)中msgid和mt(千万)中msgid相同的记录:

1.用的merge,删除200万条,用了535秒。(merge delete时,前面必须加update set)

merge into t_statbuf buf  
using (select * 
            from  t_mt 
            where ctime>=to_date('2013-04-27','yyyy-mm-dd') 
            )  mt
on(buf.msgid=mt.msgid)
when matched then
update set buf.stat=null
delete where( buf.msgid=mt.msgid)



2.我没有测试,但是别人虚拟的,并且也有关联的,只用了几十秒,所以貌似删除的时候应该不用merge,直接exists

可以这样试试:

create table tmp_t1 nologgng as
select buf.msgid from buf,mt where =;
create table tmp_mt nologging as
select * from mt;
create index ... on tmp_mt(msgid);
delete from tmp_mt mt where exists
(select 1 from tmp_t1 t1 where mt.msgid=t1.msgid);
commit;
delete from buf where exists
(select 1 from tmp_t1 t1 where buf.msgid=t1.msgid);
commit;
insert into buf 
select * from tmp_mt;
commit;



DELETE   t_statbuf m2 WHERE EXISTS(SELECT m1.msgid FROM t_mt m1 WHERE ctime>=to_date('2013-04-27','yyyy-mm-dd') AND m1.msgid=m2.msgid)



前人的经验:


merge 是比较实用,但是如果你遇到很大的数据量的更新,merge的效率也变差,你可能要做分批更新的操作,当然这种更新量也在千万级别的数据量 。

如果删除的数据小  buf和mt数据量大,就先把相同数据取出来,再用exists。


update每一条都要扫描一次


关联的结果集多 hash是快  关联的结果集少hash就慢。

两个数据差异不大的时候  关联结果集多才快  有时候两个数据表数量差异很大的时候hash也很慢  不过我试过,这种跟nested差别好像不是很大。



问:
什么叫差异不大
答:
数据量差不多
问:
几千万A 和 几亿B表 ?
hj(hash join)快些吧
如果几千 A和 几百万B当然NL(nested loop)快了
答:
如果数据关联结果集只有几百万那还是很慢的
看结果集数量
问:
结果集数量?
答:
嗯  关联的目标结果count数