我现在有2张大数据量表:表A有6万条数据,表B有20万条数据, 我做了一个存储过程,用游标遍历了表A,然后把数据一条条取出来,到表B中统计匹配的数据,每一条需要统计10种数据,然后再更新到表A上。可是这样效率非常低,存储过程执行了10多个小时还没有结束。 请高手指点下,有没有提高效率的方法呢?
解决方案 »
- SqlServer 自定义函数转换成Oracle(急,在线等)
- 有时会出现: ADODB.Recordset (0x800A0E78)对象关闭时不允许操作的错误
- 急:竖表如何实现成横表?
- 如何将一个关联查询的结果以二维表的形式输出
- select into 的问题
- [新手求救]我第一次装oracle,安装问题,折磨了我一天了,100分求救!
- 导数据库文件问问题
- 关于数据库当中跨用户建立触发器
- 哪里有关于sql语言的练习
- SOS,如果500分能够救我的话,我情愿再拿出500分,让大侠喝点茶,,,,
- 连接查询为什么出错呢?
- [高分提问] 因为 OLE DB 提供程序 'MSDAORA' 无法启动分布式事务
SORTID VARCHAR2(20) not null,
SORTNAME VARCHAR2(100),
PARENT VARCHAR2(20),
ROOT VARCHAR2(20),
TYPE1 NUMBER,
TYPE2 NUMBER,
TYPE3 NUMBER,
…………………………
TYPE15 NUMBER表B结构
ID NUMBER(10) not null,
SORTID VARCHAR2(20) not null,
CTYPE CHAR(10),
CTIME date,
…………………………
表A.sortid = 表B.sortid;表A.type1~15 = 表B.ctype ;从表A取出SORTID 到表B轮循一遍,然后算出每种type的数量,更新到表A对应的字段中
我原来的方法是[用存储过程定时统计]:
update 表A set type1 = (select count(*) from 表B where substr(sortid,1,length('||cur.sortid||')) = '||cur.sortid||') where sortid = '||cur.sortid||'
这样我用substr(a1,1,2) 不是把a1~a1b1c1的总数算出来了吗?
'update 表A set type1 = (select count(*) from 表B where sortid like '''||cur.sortid||'%'') where sortid = '''||cur.sortid||''''
如果不是,就这样写
update 表A set type1 = (select count(*) from 表B where sortid like cur.sortid||'%') where sortid = cur.sortid此外,如果是动态SQL,最好是用绑定参数方式,这样可以减少SQL语句分析的开销,如
s := 'update 表A set type1 = (select count(*) from 表B where sortid like :v1) where sortid = :v2';
...
execute immediate s using cur.sortid||'%',cur.sortid;
2、看你用了substr,不知道你是怎么建索引的,一般的索引在substr下是无效的,按照你的说法,估计你需要建N个函数索引。不过我觉得肯定还有其他方法
3、我也做过类似的统计,数据量和你的查不过,一般在几十秒可以出来结果,
create or replace procedure p_count_rev_invalid is
cursor c1 is select seg_no_min,seg_no_max,cnt from prov_segno for update of cnt;
t_c1 c1%rowtype;
l_cnt int;
begin
open c1;
loop
l_cnt:=0;
fetch c1 into t_c1;
exit when c1%notfound;
select count(1) into l_cnt from mdn
where mdn>=t_c1.seg_no_min and mdn<=t_c1.seg_no_max;
update prov_segno set cnt=l_cnt where current of c1;
end loop;
close c1;
commit;
exception
when others then
rollback;
end p_count_rev_invalid;其中在MDN表的MDN字段建有索引
然后写一个存储过程,
GetSortIDType(sortid in varchar, type1count out number, ..., type15count out number)
用它来获取某个sortid对应的所有type的数量,对于每一个sortid而言,这个存储过程的执行速度应该能接受。然后从A表中逐一取出sortid,然后调用这个存储过程,最后插入。遍历A表的效率应该是没有办法提高的
like 'x%' ==>是可以用到索引的用了组合条件语句后(加了一个and aa>0),substr反而比 like快?
----------------------------------------------------
可能是aa>0过滤掉很多记录,很就会有很少的记录返回,在这个时候全表扫描比走索引快.
你可以查看执行计划,你加了查询条件后,查询结果比不加查询条件的时候少了很多。oracle实用索引有一个计算方法,当查询的结果集占到总数据量的一定百分比后,他就将直接进行全表检索而不是索引检索。当然,你也可以强制要求进行索引检索(但不建议这么做)加了and aa>0后,会快一些,道理和以上一样,详细的可以参阅
http://matrix.org.cn/thread.shtml?topicId=26948&forumId=36
SET type1 = (
SELECT COUNT(*)
FROM 表B b
WHERE ctype='type1'
AND a.sortid=b.sortid)
WHERE a.sortid IN (SELECT sortid FROM 表B)
GO
UPDATE 表A a
SET type2 = (
SELECT COUNT(*)
FROM 表B b
WHERE ctype='type2'
AND a.sortid=b.sortid)
WHERE a.sortid IN (SELECT sortid FROM 表B)
GO
------------------------------
UPDATE 表A a
SET type15 = (
SELECT COUNT(*)
FROM 表B b
WHERE ctype='type15'
AND a.sortid=b.sortid)
WHERE a.sortid IN (SELECT sortid FROM 表B)
GO
on table (aj,aa);
基本思路如下:
update tab_A set (type1,..type15)=(select t1.type1,..t15.type15 from (
(select SORTID ,count(*) as type1 from tab_b
where ctype=type1
group by sortid) t1,
...
(select SORTID ,count(*) as type15 from tab_b
where ctype=type15
group by sortid) t15)
)
where tab_A.sortid=t1.sortid
...
and tab_A.sortid=t15.sortid