ORACLE中如果表数据量很大(M级或更大),update某个字段是很慢的(如我的HIS项目中更新历史业务流程表,160万条记录,用CURSOR来更新,1000条COMMIT一次,花了4天也没更新完),后来尝试过的改进办法有:
创新互联建站于2013年开始,是专业互联网技术服务公司,拥有项目网站设计、成都网站设计网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元澄城做网站,已为上家服务,为澄城各地企业和个人服务,联系电话:13518219792
1.把表上的LOGGING取消
2.把表上的INDEX取消
但是依然很慢,无奈下找到这个:
在这个主题问答里,ORA官方提了一种处理的办法:
1.利用CREATE table as select xxxxx的办法来生成一新表T1
2.在T1上创建与目标表一样的索引
3.把目标表删除或RENAME(注意备份以备反悔)
4.把T1改名成目标表
试了一下,果然非常地快,我的任务差不多在2Min就完成了。
如csywdk.table_room是一张大表,要删除其中bakfwid在noNewYWFW20081205中的记录,且要更新bakfwid在imp_table_room中记录的ROOM_LOC为imp_table_room.room_loc:
(1)创建新表
create table tmp_new_table_room081205 as
select t1.ROOM_ID,t1.NEWROOMID,t1.BUILDID,t1.TFH,t1.DKH,t1.BUILD_NO,t1.LAYER_NO,t1.ROOM_NO,t1.ROOM_NAME,
decode(t2.bakfwid,null,t1.ROOM_LOC,t2.room_loc)
t1.ROOM_AREA,
t1.SURTYPE,t1.LAYER_NAME,t1.DEVDEP,t1.CELL,t1.DELFLAG,t1.QXXZ,t1.SJSJLSH,t1.FD,t1.ID,t1.BAKFWID
from csywdk.table_room t1 left join imp_table_room t2 on t1.bakfwid=t2.bakfwid
where not exists(select 1 from noNewYWFW20081205 t3 where t3.bakfwid=t1.bakfwid)
(2)创建备份表
create table Table_room081205 as
select * from csywdk.table_room
(3)替换原表
drop table sde.table_room
create table sde.table_room as
select * from tmp_new_table_room081205
在这个问答里还提到一句ORA PL/SQL效率相关的话:
“能用一句语句处理的任务决不要用多句编程来实现”。
原来老是怕一句执行时,回滚段不够大,看来只能准备好硬盘为上策了
你可以写一个存储过程来执行,由于数据量大,如果直接更新,数据库UNDO表空间肯定会满,会产生异常。
过程如下,给你参考下。
CREATE OR REPLACE PROCEDURE UPDATE_TABLES
AS
TYPE T_MW IS TABLE OF ROWID;
T_T_MW T_MW;
CURSOR V_CUR IS
SELECT ROWID FROM T ;
BEGIN
OPEN V_CUR;
LOOP
FETCH V_CUR BULK COLLECT
INTO T_T_MW LIMIT 80000;
FOR C1 IN 1 .. T_T_MW.COUNT LOOP
UPDATE T NOLOGGING
SET 要改的列
WHERE ROWID=T_T_MW(C1);
END LOOP;
COMMIT;
EXIT WHEN V_CUR%NOTFOUND;
END LOOP;
CLOSE V_CUR;
COMMIT;
END;
该过程可一次提交80000行。你也可以根据需求改。
操作步骤如下:
准备数据:在excel中构造出需要的数据
2.将excel中的数据另存为文本文件(有制表符分隔的)
3.将新保存到文本文件中的数据导入到pl*sql中
在pl*sql中选择tools--text
importer,在出现的窗口中选择"Data
from
Textfile",然后再选择"Open
data
file",
在弹出的文件选择框中选中保存有数据的文本文件,此时将会看到data
from
textfile中显示将要导入的数据
4.在configuration中进行如下配置
注:如果不将"Name
in
header"勾选上会导致字段名也当做记录被导入到数据库中,从而导致数据错误
5.点击data
to
oracle,选择将要导入数据的表,并在fields中将文本中的字段与表中的字段进行关联
6.点击import按钮进行导入
7.查看导入的数据
OK,至此数据导入成功。
建议你通过某个条件把这150万条记录,分成多个部分,写个存储过程,依次执行,执行完一部分就提交一部分。
这样即即减少了对内存的要求,也防止玩意update出错,还要花费大量的时间在回滚上。
UPDATE C_TABLE C SET C.NAME1= C.NAME2 WHERE C.NAME2 IS NOT NULL AND ROWNUM = 3000;
你的条件,C.NAME2 IS NOT NULL ,所能查询出的数据始终没变,再加上ROWNUM = 3000,也是结果始终未变,要么第二次查询3000-6000,或者查询的字段NAME2发生变化,使得数据查询结果变化。
可以用游标来执行更新,也可以用update语句更新。
但是oracle没有update from语句,可以用子查询来给源数据表的字段赋值,如果需要赋多个值的话,则用括号括起来,格式:
update table_name
set (field1, field2, ... ) = (select value1, value2, ... from source_table)
where ...
而where条件中则可以用exists测试是否要更新记录。更新语句大概这样:
update A s1
set a5 = (select b6
from B s2
where s2.b1 = s1.a1 and s2.b2 = s1.a2 and s2.b3 = s1.a3 and rownum = 1)
where exists (
select b6
from B s2
where s2.b1 = s1.a1 and s2.b2 = s1.a2 and s2.b3 = s1.a3 and rownum = 1
)
即赋值子句和where条件是类似的。