作为更大处理项目的一部分,我正在尝试找到一种更好的方法将数据从表中提取到另一个表中。我认为我可以通过 BULK COLLECT 和 FORALL 来完成,并获得显着的速度,但我认为我不能使用 BULK COLLECT 处理单个列引用......
我有一个关于继承的数据/应用程序迁移项目(MSSQL 到 Oracle 11.2)。我正在尝试优化和端到端检查...该过程的第一步是将遗留数据(数据库表,4.5M 记录,170 列,全部为字符串格式)导入另一个表。
最初的转换是基于游标的,逐行循环,每一列都经过至少一个用于清除/转换的函数。它有效,但在测试系统上花费了太长时间——用非常简单的函数将 450 万条记录从一个表转换到另一个表需要超过 12 个小时。在我可以访问的本地实现中,它们最终限制为 13000 个单元 ID 号 ID 超过 220k 记录。
我在我的笔记本电脑上设置了一个更有限的开发系统来测试替代技术——并且可以获得超过 5 倍的导入速度,但这仍然是光标/行。我已将表设置为 NOLOGGING 并使用 APPEND 提示。我已经测试了有/没有索引。我不能用那个尺寸的桌子做 SELECT INTO —— 它只是窒息。
还有另一种/更好的技术吗?我还能如何提高转换速度?我用 BULK COLLECT 做错了吗(即有没有办法引用各个字段?)
如果有人有任何见解,请插播!我包含了一个非常精简的过程版本,所以我可以展示我的使用尝试。同样的事情(几乎)作为常规游标循环运行,只是不使用 FORALL 和 (i) 下标。我得到的错误是 ORA-00913: Too Many Values。我已经完成了完整的插入语句,将字段与值匹配。我检查了数据转换函数——它们适用于常规列作为参数。我想知道他们是否因为下标而无法使用 BULK COLLECT 和/或 FORALL ?
更新信息:
这是在一个访问受限的系统上,直到现在(等待帐户),我一直不得不通过在本地系统上运行来远程诊断“真实”(客户)DEV系统——分析代码,数据,时间等。我的建议是由另一位开发人员提出的,他会反馈我的结果。严重地。但是...... @Mark,@Justin - 通常情况下,我会摆脱任何游标而不是?绝对?需要,并尽可能使用 SELECT INTO。这通常是我对旧 PL/SQL 代码的第一个建议......(“为什么。所以。光标?”穿着小丑化妆)。这是我在本地系统上尝试的第一件事,但它只是让服务器慢下来,我退出了测试。那是在减少 NOLOGGING 实施之前 - 这就是我
在查看了时间、查询、连接、索引和哭泣之后,我推荐了 NOLOGGING 并转换为 INSERT /*+ APPEND */ -- 这在其他进程中赢得了时间,主要是由连接构建的表。
回复:“OID <= '000052000'” - 当他们在 cust 开发系统上设置第一次转换代码时,他们必须限制从 PMS_OHF 表转换的记录数量。最初,他们可以在合理的时间内处理 13000 个人员标识符。这 13000 个 ID 将在大约 220K 记录中,所以,当我加入时,这就是他们正在移动的内容。一些重写、加入更正和 NOLOGGING/Insert Append 产生了足够大的差异,他们继续进行。在本地系统上,我认为 13000 太小了——我认为我无法与遗留结果进行有意义的比较——所以我提高了它,并提高了它。我应该勇敢地尝试在笔记本电脑开发系统上进行全面转换——在这里我至少可以通过 EM 观察正在发生的事情......政府不会 不允许他们的 DBA 使用它。(!?)
更大的信息:-- 在再次思考 00913 错误并回想其他项目之后,我意识到早期的错误是当多个元素被传递给一个期望单个元素的函数时......这让我回到了我试图使用下标BULK COLLECT 循环中的字段名称。我重新观看了几个 Steven Feuerstein YT 的演讲,我认为它终于融入了。简单的网络示例......我正在水平制作我的类型,而不是垂直(反之亦然)......为了得到我的函数调用才能工作,我想我必须为每个字段创建一个类型,以及该类型的数组/表。突然(170 次)我想我会看一些关于手动并行的 Tom Kyte 课程,然后问 wx 我可以访问新的(11.2?)DBMS_PARALLEL_EXECUTE 接口——我对此表示怀疑。还,不知道更多关于 cust 开发系统的信息,除了最好称为“不充分”的描述,我不知道 wx //ism 会是一个巨大的帮助。我需要阅读 //ism
我所知道的是,我必须完成一些完整的运行,否则我会不愿意说我们的结果“足够接近”遗留结果。对于我们的测试,我们可能没有太多选择来进行多天的完整运行。
PROCEDURE CONVERT_FA IS
CURSOR L_OHF IS -- Cursor used to get SOURCE TABLE data
SELECT *
FROM TEST.PMS_OHF -- OHF is legacy data source
where OID <= '000052000' -- limits OHF data to a smaller subset
ORDER BY ID ;
L_OHF_DATA TEST.PMS_OHF%ROWTYPE;
L_SHDATA TEST.OPTM_SHIST%ROWTYPE;
Type hist_Array is table of TEST.PMS_OHF%ROWTYPE;
SHF_INPUT hist_array ;
Type Ohist_Array is table of TEST.OPTM_SHIST%ROWTYPE;
TARG_SHIST ohist_Array ;
n_limit number := 1000 ;
BEGIN
begin
OPEN L_OHF;
LOOP
FETCH L_OHF BULK COLLECT INTO SHF_INPUT LIMIT n_limit ;
FORALL i in 1 .. n_limit
INSERT INTO TEST.OPTM_SHIST
( -- There are 170 columns in target table, requiring diff't xformations
RECORD_NUMBER , UNIQUE_ID , STRENGTH_YEAR_MONTH , FY , FM , ETHNIC ,
SOURCE_CODE_CURR , SOURCE_CODE_CURR_STAT ,
-- ... a LOT more fields
DESG_DT_01 ,
-- and some place holders for later
SOURCE_CALC , PSID , GAIN_CURR_DT_CALC
)
values
( -- examples of xformatiosn
SHF_INPUT.ID(i) ,
'00000000000000000000000' || SHF_INPUT.IOD(i) ,
TEST.PMS_UTIL.STR_TO_YM_DATE( SHF_INPUT.STRYRMO(i) ) ,
TEST.PMS_UTIL.STR_TO_YEAR( SHF_INPUT.STRYRMO(i) ) ,
TEST.PMS_UTIL.STR_TO_MONTH( SHF_INPUT.STRYRMO(i) ) ,
TEST.PMS_UTIL.REMOVE_NONASCII( SHF_INPUT.ETHNIC(i) ) ,
-- ... there are a lot of columns
TEST.PMS_UTIL.REMOVE_NONASCII( SUBSTR( SHF_INPUT.SCCURPRICL(i),1,2 ) ) ,
TEST.PMS_UTIL.REMOVE_NONASCII( SUBSTR( SHF_INPUT.SCCURPRICL(i),3,1 ) ) ,
-- an example of other transformations
( case
when (
(
SHF_INPUT.STRYRMO(i) >= '09801'
AND
SHF_INPUT.STRYRMO(i) < '10900'
)
OR
(
SHF_INPUT.STRYRMO(i) = '10901'
AND
SHF_INPUT.DESCHGCT01(i) = '081'
)
)
then TEST.PMS_UTIL.STR_TO_DATE( SHF_INPUT.DESCHGCT01(i) || SHF_INPUT.DESCHGST01(i) )
else TEST.PMS_UTIL.STR_TO_DATE( SHF_INPUT.DESCHGDT01(i) )
end ),
-- below are fields that will be filled later
null , -- SOURCE_CALC ,
SHF_INPUT.OID(i) ,
null -- GAIN_CURR_DT_CALC
) ;
EXIT WHEN L_OHF%NOTFOUND; -- exit when last row is fetched
END LOOP;
COMMIT;
close L_OHF;
END;
end CONVERT_OHF_FA;