所以我正在工作中处理这个项目,我注意到很多人使用 INSERT INTO SELECT 方法:
INSERT INTO candy_tbl (candy_name,
candy_type,
candy_qty)
SELECT food_name,
food_type,
food_qty
FROM food_tbl WHERE food_type = 'C';
但是,我使用以下光标方法:
FOR rec IN ( SELECT
food_name,
food_type,
food_qty
FROM food_tbl WHERE food_type = 'C')
LOOP INSERT INTO candy_tbl(candy_name,
candy_type,
candy_qty)
VALUES(rec.food_name,
rec.food_type,
rec.food_qty)
END LOOP;
这将进入 PL/SQL 包。我的问题是,哪种方法通常是“首选”方法以及何时?我通常选择游标方法,因为它在异常处理方面给了我更多的灵活性。但是,我可以看到插入大量记录时可能会出现性能问题。
FOR 循环需要从 CURSOR 中获取每一行。循环中的INSERT将一一发生。PLSQL在PLSQL引擎中运行,SQL在SQL引擎中运行,因此FOR循环: - 在PLSQL引擎中运行 - 将查询发送到 SQL 引擎以执行查询并打开游标,然后切换回 PLSQL 引擎 - 每个循环从 CURSOR 执行 FETCH,然后执行 INSERT,这意味着返回到 SQL 引擎,然后返回到 PLSQL 引擎
SQL 和 PLSQL 之间的每次切换以及每次 FETCH 都很昂贵。
INSERT INTO SELECT 将被发送到 SQL 引擎一次并在那里运行直到完成,然后返回到 PLSQL。
还存在其他优点,但这是这两种方法之间的主要 PLSQL 区别。
第一个更快,因为它基本上是单个事务,也称为基于集合的处理。
后者按行操作,对于非常大的表,性能会有很大差异。
如果您确实需要游标处理的灵活性但需要更好的性能,则可以使用第三个中间选项 - BULK COLLECT 和 FORALL 以及保存异常选项。 然而,代价是代码复杂性更高。以下是基本结构。
declare
exception error_in_forall ;
pragma exception_init (error_in_forall, -24381);
cursor c_select is ( select ... ) ;
type c_array_type table of c_select%rowtype;
v_select_data c_array_type ;
begin
open c_select;
loop
fetch c_select
bulk collect
into v_select_data;
forall rdata in v_select_data.first .. v_select_data.last save exceptions
insert into ( ... ) values (v_select_data(rdata).column ... ) ;
exceptions
when error_in_forall then
<Process Oracle generated bulk error collection >
end ;
完成后,如果在执行插入期间发生任何错误,则会触发一次异常。 Oracle 已构建一个 SQL%BULK_EXCEPTIONS 集合,其中包含索引值和每个错误代码。 有关详细信息,请参阅适用于您的版本的 PL/SQL 语言参考。
U 可以尝试在 for rec 之前为第一个查询添加 Begin,并在结束循环之后添加 END,如下所示
开始 对于录音输入(选择 食物名称, 食物类型, 食物数量 来自 food_tbl WHERE food_type = 'C') 循环插入 candy_tbl(candy_name, 糖果类型, 糖果数量) 值(rec.food_name, 记录.食物类型, 记录食物数量) 结束循环; 结束;