MySQL支持INSERT ... VALUES()多值插入和UPDATE JOIN多表更新,性能好、语法简洁;SQL Server必须用MERGE+事务包裹;PostgreSQL用UPDATE ... FROM;Oracle用FORALL或MERGE。

MySQL里用INSERT ... VALUES()和UPDATE JOIN做批量操作最直接
别绕弯写游标或循环,MySQL原生支持多值插入和多表更新,性能好、语法干净。重点是别把SQL Server或PostgreSQL的写法硬搬过来。
-
INSERT INTO t (a,b) VALUES (1,'x'),(2,'y'),(3,'z')——这是标准批量插入,一次最多受max_allowed_packet限制,通常建议单次≤2000行 -
UPDATE orders o JOIN customers c ON o.customer_id = c.id SET o.status = 'shipped' WHERE c.country = 'CN'——JOIN必须紧跟UPDATE后,不能带FROM;被更新表名(如orders)必须显式写出,不能只用别名 - 常见错误:
UPDATE t1 SET t1.col = t2.val FROM t1 JOIN t2 ON ...会报ERROR 1064,MySQL不认这种写法 - 安全起见,先用
SELECT COUNT(*) FROM orders o JOIN customers c ... WHERE c.country = 'CN'验证匹配行数,再执行UPDATE
SQL Server必须用MERGE或分批UPDATE+TRYCATCH
MERGE不是可选项,是唯一能安全实现“根据源数据批量更新目标表”的语法。硬写UPDATE JOIN会直接报错Incorrect syntax near the keyword 'JOIN'。
-
MERGE orders AS t USING (SELECT id, new_status FROM staging) AS s ON t.id = s.id WHEN MATCHED THEN UPDATE SET t.status = s.new_status;——ON子句定义匹配逻辑,WHEN MATCHED才触发UPDATE,漏写会语法报错 - 事务必须包裹:
BEGIN TRY BEGIN TRANSACTION ... COMMIT; END TRY BEGIN CATCH ROLLBACK; THROW; END CATCH,否则出错时部分更新已提交,无法回滚 - 传参别用逗号拼接字符串,改用
@batch_ids TABLE(id INT)表变量或JSON(SQL Server 2016+),避免注入和解析开销 - 大批量时拆成每500行一批,用
WHERE id IN (SELECT TOP 500 id FROM @batch_ids ORDER BY id)加ORDER BY id防死锁
PostgreSQL靠UPDATE ... FROM和临时表配合
PostgreSQL不支持UPDATE JOIN,但UPDATE ... FROM语义等价,且更灵活。注意DO块不能直接BEGIN/COMMIT,得封装进函数。
-
UPDATE orders SET status = s.new_status FROM (VALUES (1,'shipped'),(2,'cancelled')) AS s(id, new_status) WHERE orders.id = s.id——FROM后跟VALUES或子查询,字段需一一对应 - 大批次建议先
CREATE TEMP TABLE batch_ids (id INT PRIMARY KEY),再COPY或INSERT载入ID,最后用UPDATE ... FROM batch_ids关联更新 - 别在DO块里裸写批量逻辑:
DO $$ BEGIN UPDATE ...; END $$一旦失败整个回滚,没法定位哪条出错;应写成CREATE OR REPLACE FUNCTION batch_update() RETURNS void AS $$ ... $$ LANGUAGE plpgsql - 并发高时加
pg_advisory_xact_lock(123)做轻量级协调,避免多个会话同时处理同一组ID
Oracle用FORALL + BULK COLLECT或MERGE避免PL/SQL慢循环
Oracle里逐行EXECUTE IMMEDIATE是性能黑洞,哪怕只有几百行也明显变慢。FORALL才是批量操作的核心机制。
-
FORALL i IN 1..ids.COUNT UPDATE orders SET status = 'shipped' WHERE id = ids(i)——ids是PL/SQL数组,FORALL把整个数组转成一条底层批量操作,比循环快一个数量级 - 源数据来自查询时,先
BULK COLLECT INTO到数组:SELECT id BULK COLLECT INTO ids FROM staging WHERE processed = 0,再FORALL更新 - 需要“存在则更新、不存在则插入”时,用
MERGE INTO target USING source ON (...) WHEN MATCHED THEN UPDATE ... WHEN NOT MATCHED THEN INSERT ...,比分开写INSERT/UPDATE更原子 - 注意
SAVE EXCEPTIONS子句:当某几行违反约束时,其余行仍可提交,配合SQL%BULK_EXCEPTIONS捕获具体错误行

















