You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过存储过程并行运行五万余条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);
通用优化建议
  1. 优先合并重复逻辑:如果很多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;

这种合并后的语句可以让数据库自动优化并行执行,减少执行开销。

  1. 控制分组大小:不要每条SQL单独开任务(开销太大),建议每50-200条SQL组成一组,平衡并行度和系统开销。

  2. 实时监控负载:并行执行会增加CPU、IO压力,要实时监控数据库指标,一旦负载过高就降低并行度。

内容的提问来源于stack exchange,提问作者Niloy Datta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:06:31