如何通过存储过程并行运行五万余条INSERT SQL语句
嘿,这个场景我太熟悉了——5万多条串行跑的INSERT语句,肯定慢到让人抓头!下面我根据不同主流数据库给你梳理具体的并行改造方案,你可以对着自己用的库来调整:
按数据库类型的并行改造方案
1. Oracle 数据库
方案:用DBMS_SCHEDULER创建分组并行任务
把5万条SQL按一定数量分组(比如每100条一组),给每组创建独立的调度任务,让它们并行执行:
DECLARE v_job_name VARCHAR2(100); v_sql CLOB; v_group_size NUMBER := 100; -- 每组包含的SQL数量,可根据数据库负载调整 v_total_jobs NUMBER := CEIL(50000 / v_group_size); BEGIN FOR i IN 1..v_total_jobs LOOP v_job_name := 'TERR_INSERT_JOB_' || i; -- 这里需要替换成对应分组的实际SQL语句,建议从存储过程的SQL列表中按范围提取拼接 v_sql := 'INSERT INTO TERR_CUST (select cnt from test a); ' || 'INSERT INTO TERR_CUST (select cnt from test a inner join test b on a.name=b.name); '; DBMS_SCHEDULER.CREATE_JOB( job_name => v_job_name, job_type => 'PLSQL_BLOCK', job_action => 'BEGIN ' || v_sql || ' END;', start_date => SYSTIMESTAMP, enabled => TRUE, auto_drop => TRUE -- 任务完成后自动清理,避免垃圾任务堆积 ); END LOOP; END; /
注意事项
- 并行度别贪多:建议根据服务器CPU核心数设置,一般不超过核心数的2倍,避免把数据库打垮
- 提前处理数据冲突:如果INSERT有重复数据风险,要先调整约束,或者用
INSERT ... ON DUPLICATE KEY UPDATE(如果适用)避免任务失败
2. SQL Server 数据库
方案1:用PowerShell批量启动并行sqlcmd进程
先把5万条SQL拆分成多个小文件(比如每个文件100条),然后用PowerShell脚本同时启动多个sqlcmd进程执行:
# 替换成你的SQL文件路径、数据库连接信息 $sqlFilePath = "C:\split_terr_sql\" $serverName = "YourDBServer" $dbName = "YourDatabase" $userName = "YourUser" $password = "YourPass" $sqlFiles = Get-ChildItem "$sqlFilePath*.sql" foreach ($file in $sqlFiles) { # 启动独立进程执行SQL文件,实现并行 Start-Process sqlcmd -ArgumentList "-S $serverName -d $dbName -U $userName -P $password -i $($file.FullName)" -NoNewWindow -PassThru }
方案2:用SQL Server Agent创建多作业并行
把分组后的SQL分别放到多个Agent作业里,然后用sp_start_job同时启动这些作业,实现并行执行。
3. PostgreSQL 数据库
方案:用pg_background扩展异步执行分组任务
先安装pg_background扩展,然后分组异步执行SQL:
-- 先安装扩展(需要超级权限) CREATE EXTENSION IF NOT EXISTS pg_background; DO $$ DECLARE v_sql TEXT; v_group_size INT := 100; v_total_groups INT := CEIL(50000 / v_group_size); BEGIN FOR i IN 1..v_total_groups LOOP -- 拼接对应分组的SQL语句 v_sql := 'INSERT INTO TERR_CUST (select cnt from test a); INSERT INTO TERR_CUST (select cnt from test a inner join test b on a.name=b.name);'; -- 异步执行该组SQL,不阻塞当前会话 PERFORM pg_background_launch(v_sql); END LOOP; END $$;
监控任务状态
可以用下面的语句查看异步任务的执行结果:
SELECT * FROM pg_background_result(pid);
通用优化建议
- 优先合并重复逻辑:如果很多INSERT的查询逻辑重复,直接把所有SELECT合并成一个大INSERT,效率会比多个小INSERT高很多:
INSERT INTO TERR_CUST SELECT cnt FROM test a UNION ALL SELECT cnt FROM test a INNER JOIN test b ON a.name=b.name UNION ALL SELECT cnt FROM test a INNER JOIN test b ON a.name=b.name INNER JOIN test c ON a.name=c.name UNION ALL SELECT cnt FROM test b;
这种合并后的语句可以让数据库自动优化并行执行,减少执行开销。
控制分组大小:不要每条SQL单独开任务(开销太大),建议每50-200条SQL组成一组,平衡并行度和系统开销。
实时监控负载:并行执行会增加CPU、IO压力,要实时监控数据库指标,一旦负载过高就降低并行度。
内容的提问来源于stack exchange,提问作者Niloy Datta
相关产品推荐
相关产品推荐

