Sql 具有超过1000万条记录的快速更新数据库
我对SQL相当陌生,不知道是否有人可以帮助我 我有一个数据库,大约有1000万行 我需要制作一个脚本,查找包含一些空字段的记录,然后将其更新为某个值 执行一个简单的update语句的问题是,它会占用回滚空间 我在四处阅读,我需要使用批量收集和获取 我的想法是一次获取10000条记录,更新、提交并继续获取 我试着在谷歌上寻找例子,但我还没有找到任何东西 有什么帮助吗 谢谢 这就是我到目前为止所做的:Sql 具有超过1000万条记录的快速更新数据库,sql,database,oracle,plsql,toad,Sql,Database,Oracle,Plsql,Toad,我对SQL相当陌生,不知道是否有人可以帮助我 我有一个数据库,大约有1000万行 我需要制作一个脚本,查找包含一些空字段的记录,然后将其更新为某个值 执行一个简单的update语句的问题是,它会占用回滚空间 我在四处阅读,我需要使用批量收集和获取 我的想法是一次获取10000条记录,更新、提交并继续获取 我试着在谷歌上寻找例子,但我还没有找到任何东西 有什么帮助吗 谢谢 这就是我到目前为止所做的: DECLARE CURSOR rec_cur IS SELECT DATE_ORI
DECLARE
CURSOR rec_cur IS
SELECT DATE_ORIGIN
FROM MAIN_TBL WHERE DATE_ORIGIN IS NULL;
TYPE date_tab_t IS TABLE OF DATE;
date_tab date_tab_t;
BEGIN
OPEN rec_cur;
LOOP
FETCH rec_cur BULK COLLECT INTO date_tab LIMIT 1000;
EXIT WHEN date_tab.COUNT() = 0;
FORALL i IN 1 .. date_tab.COUNT
UPDATE MAIN_TBL SET DATE_ORIGIN = '23-JAN-2012'
WHERE DATE_ORIGIN IS NULL;
END LOOP;
CLOSE rec_cur;
END;
我想我明白你想做什么了。关于下面的代码与您的代码之间的差异,我想提出一些观点 您的forall循环将不使用索引。通过使用rowid更新您的表,这很容易解决。 通过在每次forall之后提交,您可以减少所需的撤销量;但如果出现问题,则更难回滚。虽然逻辑上,你的查询可以轻松地在中间重新启动,而不损害你的目标。 Rowid很小,一次至少收集25k;如果不是10万。 不能在Oracle中为空索引。关于stackoverflow有很多问题,您需要更多信息。在nvldate_origin上的函数索引,作为一个松散的示例,“x”将提高选择数据的速度。这也意味着您实际上不必使用表本身。您只能从索引中进行选择。 您的日期数据类型似乎是字符串。我保留了这个,但这不明智。 如果您可以让某人增加撤消表空间的大小,那么直接更新会更快。 假设根据您的评论,date_origin是一个日期,则索引应位于以下位置:
nvl(date_origin,to_date('absolute_minimum_date_in_Oracle_as_a_string','yyyymmdd'))
我目前无法访问数据库,但要查找amdiOaas,请运行以下查询:
select to_date('0001','yyyy') from dual;
这会给你带来一个有用的错误
PL/SQL开发人员中的工作示例
create table main_tbl as
select cast( null as date ) as date_origin
from all_objects
;
create index i_main_tbl
on main_tbl ( nvl( to_date(date_origin,'yyyy-mm-dd')
, to_date('0001-01-01' ,'yyyy-mm-dd') )
)
;
declare
cursor c_rec is
select rowid
from main_tbl
where nvl(date_origin,to_date('0001-01-01','yyyy-mm-dd'))
= to_date('0001-01-01','yyyy-mm-dd')
;
type t__rec is table of rowid index by binary_integer;
t_rec t__rec;
begin
open c_rec;
loop
fetch c_rec bulk collect into t_rec limit 50000;
exit when t_rec.count = 0;
forall i in t_rec.first .. t_rec.last
update main_tbl
set date_origin = to_date('23-JAN-2012','DD-MON-YYYY')
where rowid = t_rec(i)
;
commit ;
end loop;
close c_rec;
end;
/
那么,您尝试了单个UPDATE语句,但它生成了一个错误?确切的错误是什么?如果错误是您的撤消空间不足,您是否要求DBA增加撤消空间?1000万行并不是很多-您的数据库的大小确实应该能够处理您想要增加的合理工作负载,而不是试图编写代码来节省几MB的磁盘空间。我认为您的做法是正确的。发布一些代码,可能会有人对其进行评论。数据库是一个生产服务器,所以我们还没有完成单个更新语句,但根据我的经验,它以前已经崩溃了…是否仍有可能以大容量获取方式执行此操作?我在底部添加了到目前为止的内容,我得到了以下错误:PLS-00435:DML语句没有绑定中的大容量不能在内部使用,因为您当前的代码没有真正意义。首先,rec_cur游标被定义为仅返回null:它不提供有关要更新的记录的任何信息。其次,您的更新在WHERE子句中没有任何内容将其限制为要更新的记录;它只是做完整的原始更新,包括所有记录。第三,我不认为这种方法会减少您所需的撤消空间,因为您的事务仍将和以前一样大。谢谢Ben!这似乎是一个很好的方法,出于某种原因,代码首先在t_rec。。t_rec.last loop PLS-00103:在期望一个following@xela_austin那是因为我犯了最常见的甲骨文错误。forall不需要循环;我已经更新了我的答案。有关更多文档,请参阅。再次感谢!现在它说ORA-01858:一个非数字字符被发现在一个数字的地方。。这种情况发生在将c_rec批量收集到t_rec limit 50000中@xela_austin,我的代码中没有错误。查看文档。我只能猜测您已经编写了50000个类型,或者没有将该类型创建为rowid类型等等。。。或者你的约会实际上是一个数字,而不是一个日期或一个字符。我检查了3个案例,但仍然没有运气。。我用的是50000而不是50000,类型是rowid…我用蟾蜍在桌子上做了一个描述,dat_origin Column类型是DATE…:/