Oracle 利用储存过程插入循环插入大量数据方法

本文通过实测分析了10万至200万条数据在不同配置下的插入性能,展示了ORACLE数据库在大规模数据操作时的表现,并提供了一个有效的插入语句模板。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


当我们进行测试数据或者进行某种大数据量的时候,可以用一下语句进行大批量插入,

通过我的测试,10万条数据插入时间为7秒左右,100万条记录插入时间为65秒,200万插入为150秒。

我机器配置为 CPU I5 2450M 内存4G 硬盘 西部数据500G 5400转 操作系统为WIN7 64位 ,数据库为ORACLE 11G 64位 插入测试工具为PL\SQL 9.0


declare
i integer; --定义变量
begin
i := 1;
loop
/* 插入数据 */
insert into USER (yhbh, yhmc, yhmm, bmbh, yhzt, zcsj, zjdlsj, yhks, yhzw, yhms)
values
(TO_CHAR('99999999' + i),
'username',
'password',
'1',
'1',
sysdate,
sysdate,
'研发中心',
'产品经理',
'高级软件工程师');
/* 参数递增 */
i := i + 1;
/* 停止条件 */
exit when i > 2000000;
end loop;
commit;
end;


<think>我们正在讨论Oracle存储过程循环插入数据的不同方法。根据引用内容,我们可以总结出几种常见的循环插入方式: 1. **WHILE循环**:通过设置循环变量,在满足条件时执行插入操作,并更新循环变量。 2. **FOR循环**:使用预定义的循环次数范围(如1..100),简化循环控制。 3. **游标循环**:虽然引用中没有直接示例,但这也是常见方式,通过游标逐行处理数据插入。 下面将详细说明这些方法,并给出示例。 --- ### 1. WHILE 循环 **特点**:需要显式声明循环变量,并在循环体内更新变量值。 **语法**: ```sql DECLARE 变量声明; BEGIN WHILE 条件 LOOP 插入语句; 更新循环变量; END LOOP; COMMIT; END; ``` **示例**(参考引用[1]): ```sql CREATE OR REPLACE PROCEDURE test IS v_id INT := 1001; -- 初始化变量 BEGIN WHILE v_id <= 1005 LOOP INSERT INTO account (ACCOUNT_ID, USERNAME, PASSWORD) VALUES (v_id, '小明' || v_id, 'b789e083a23eb59c92e1774ebf33e6b3'); v_id := v_id + 1; -- 变量自增 END LOOP; COMMIT; END; ``` > 说明:循环插入5条数据,每次插入后`v_id`增加1,直到`v_id>1005`时退出循环[^1]。 --- ### 2. FOR 循环(数值范围) **特点**:无需显式声明循环变量,自动按指定次数循环。 **语法**: ```sql BEGIN FOR 循环变量 IN 起始值..结束值 LOOP 插入语句; END LOOP; COMMIT; END; ``` **示例**(参考引用[2]): ```sql CREATE OR REPLACE PROCEDURE insert_computers IS BEGIN FOR i IN 1..100 LOOP -- i自动从1递增到100 INSERT INTO computers (comNo, compModel, buyTime, price, owner) VALUES (i, 'Model-' || i, SYSDATE, i * 100, 'Owner-' || i); END LOOP; COMMIT; END; ``` > 注意:循环变量`i`无需提前声明,且作用域仅在循环体内[^2]。 --- ### 3. 游标循环(逐行处理) **特点**:适合基于已有表数据生成新数据插入的场景。 **语法**: ```sql DECLARE CURSOR 游标名 IS SELECT语句; BEGIN FOR 记录变量 IN 游标名 LOOP 插入语句(使用记录变量.字段名); END LOOP; COMMIT; END; ``` **示例**(参考引用[3]的思路): ```sql CREATE OR REPLACE PROCEDURE sync_data IS CURSOR cur_users IS SELECT user_id, user_name FROM source_table; -- 定义游标 BEGIN FOR rec IN cur_users LOOP -- 自动遍历游标 INSERT INTO target_table (id, name, create_time) VALUES (rec.user_id, rec.user_name, SYSDATE); END LOOP; COMMIT; END; ``` > 说明:通过游标逐行读取`source_table`的数据,并插入到`target_table`中[^3]。 --- ### 4. 性能优化建议 1. **批量提交**:避免每次循环都提交(如引用[3]中每次循环COMMIT),改为循环结束后一次性提交,减少I/O开销。 2. **批量绑定**:使用`FORALL`语句(BULK COLLECT)替代循环插入幅提升性能(示例见下文)。 **FORALL 示例**: ```sql CREATE OR REPLACE PROCEDURE bulk_insert IS TYPE id_tab IS TABLE OF NUMBER; TYPE name_tab IS TABLE OF VARCHAR2(50); ids id_tab; names name_tab; BEGIN -- 假设从某表查询出数据 SELECT employee_id, first_name BULK COLLECT INTO ids, names FROM employees WHERE department_id = 80; FORALL i IN 1..ids.COUNT INSERT INTO target_table (id, name) VALUES (ids(i), names(i)); COMMIT; END; ``` --- ### 总结对比 | **方法** | **适用场景** | **优点** | **缺点** | |----------------|--------------------------------|-----------------------------|-----------------------| | **WHILE循环** | 循环次数不确定或复杂条件 | 条件控制灵活 | 需手动管理循环变量 | | **FOR循环** | 固定次数的循环 | 语法简洁,无需变量管理 | 仅支持简单数值范围 | | **游标循环** | 基于查询结果逐行处理 | 天然支持数据驱动 | 性能较低(可改用批量) | | **FORALL** | 批量数据插入 | 极高性能(减少上下文切换) | 代码复杂度较高 | --- ### 相关问题 1. 如何在游标循环中使用`%ROWTYPE`简化记录定义? 2. 使用`FORALL`插入时遇到`ORA-24381`错误(数组不一致)如何解决? 3. 循环插入大量数据时,如何避免UNDO表空间不足? 4. 存储过程中如何动态生成插入数据(如随机字符串、序列值)? > 引用说明:WHILE循环示例参考引用[1][^1],FOR循环示例参考引用[2][^2],游标处理逻辑参考引用[3][^3]。</think>以下是Oracle存储过程中实现循环插入数据的多种方法总结,结合引用内容及最佳实践: --- ### 一、WHILE 循环插入 **特点**:需手动控制循环变量和终止条件 **语法结构**: ```sql CREATE OR REPLACE PROCEDURE proc_name IS 变量声明; BEGIN WHILE 循环条件 LOOP INSERT语句; 变量更新; END LOOP; COMMIT; END; ``` **示例**(引用[1][^1]): ```sql CREATE OR REPLACE PROCEDURE test IS v_id INT := 1001; -- 初始化变量 BEGIN WHILE v_id <= 1005 LOOP INSERT INTO account (ACCOUNT_ID, USERNAME, PASSWORD) VALUES (v_id, '小明' || v_id, 'b789e083a23eb59c92e1774ebf33e6b3'); v_id := v_id + 1; -- 手动递增 END LOOP; COMMIT; END; ``` --- ### 二、FOR 循环插入 **特点**:自动管理循环变量,无需手动递增 **语法结构**: ```sql BEGIN FOR 循环变量 IN 起始值..结束值 LOOP INSERT语句; END LOOP; COMMIT; END; ``` **示例**(引用[2][^2]): ```sql CREATE OR REPLACE PROCEDURE insert_computers IS BEGIN FOR i IN 1..100 LOOP -- i自动从1递增到100 INSERT INTO computers (comNo, compModel, buyTime, price, owner) VALUES (i, 'Model-' || i, SYSDATE, i*1000, 'Owner-' || i); END LOOP; COMMIT; END; ``` --- ### 三、游标循环插入 **特点**:基于查询结果动态插入 **语法结构**: ```sql DECLARE CURSOR 游标名 IS SELECT语句; BEGIN FOR 记录变量 IN 游标名 LOOP INSERT INTO 表A SELECT ... FROM 表B WHERE 条件; END LOOP; COMMIT; END; ``` **示例**(引用[3][^3]优化版): ```sql CREATE OR REPLACE PROCEDURE sync_data IS CURSOR cur_users IS SELECT userid, username FROM source_table; BEGIN FOR rec IN cur_users LOOP INSERT INTO target_table (flduserid, fldusername, fldlogindate) VALUES (rec.userid, rec.username, SYSDATE); END LOOP; COMMIT; END; ``` --- ### 四、BULK COLLECT + FORALL(高性能方案) **特点**:批量处理,性能提升10倍以上 **语法结构**: ```sql DECLARE TYPE 集合类型 IS TABLE OF 表%ROWTYPE; 集合变量 集合类型; BEGIN SELECT * BULK COLLECT INTO 集合变量 FROM 源表; FORALL i IN 1..集合变量.COUNT INSERT INTO 目标表 VALUES 集合变量(i); COMMIT; END; ``` **示例**: ```sql CREATE OR REPLACE PROCEDURE bulk_insert IS TYPE t_emp_tab IS TABLE OF employees%ROWTYPE; v_emps t_emp_tab; BEGIN SELECT * BULK COLLECT INTO v_emps FROM employees WHERE department_id = 80; FORALL i IN 1..v_emps.COUNT INSERT INTO emp_archive VALUES v_emps(i); COMMIT; END; ``` --- ### 五、性能对比与建议 | **方法** | 适用场景 | 性能 | 复杂度 | |----------------|-------------------------|------|--------| | WHILE循环 | 简单固定次数插入 | ★★☆ | 低 | | FOR循环 | 已知次数的序列插入 | ★★★ | 低 | | 游标循环 | 基于查询结果的动态插入 | ★★☆ | 中 | | BULK COLLECT | 数据插入(>1000行) | ★★★ | 高 | **最佳实践**: 1. 小数据量(<100行):优先用FOR循环 2. 中数据量(100-1000行):游标循环 3. 数据量(>1000行):必须用BULK COLLECT 4. **避免在循环内COMMIT**:在循环结束后一次性提交(事务过时需分批) --- ### 相关问题 1. 如何在FOR循环中使用`%ROWTYPE`声明记录变量? 2. 使用BULK COLLECT时遇到`ORA-01555`快照过旧错误如何解决? 3. 游标循环和BULK COLLECT的性能差异机制是什么? 4. 如何动态生成循环插入的SQL语句(如根据日期分区)? > 引用说明:WHILE循环示例参考引用[1][^1],FOR循环结构参考引用[2][^2],游标处理逻辑优化自引用[3][^3]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值