大型数据存储和数据流(ETL,迁移)的出现不仅要求加载数十万行,还要求确保数据要么完全加载,要么什么都不加载。在SQL中,这是通过在事务中使用原子bulk操作来实现的。
在批量插入(Bulk Insert)时,错误的风险更高 — 一行不正确的记录可能会破坏整个加载过程或导致部分插入。这对于金融、物流和其他关键系统来说是不可接受的。
实践是将bulk操作包裹在事务中,使用合适的特殊命令(BULK INSERT,COPY)并捕获/记录错误。重要的是:如果任何行出错,则整个块会回滚:
SQL Server的示例:
BEGIN TRAN; BULK INSERT Customers FROM 'C:\data\customers.csv' WITH ( FIELDTERMINATOR = ',', ROWTERMINATOR = ' ', FIRSTROW = 2 ); IF @@ERROR <> 0 ROLLBACK TRAN; ELSE COMMIT TRAN;
PostgreSQL(使用COPY的示例):
BEGIN; COPY products FROM '/tmp/products.csv' DELIMITER ',' CSV HEADER; COMMIT;
关键特性:
在Bulk Insert中,事务大小会影响性能和锁定吗?
是的,当数据量过大时,可能会导致长时间的锁定,事务日志溢出并减慢服务器。最好是分批加载,例如每个事务10000行。
Bulk Insert在所有数据库中是否总是默认是事务性的?
不是,在某些数据库(例如MySQL)中,bulk insert命令并不总是自动原子 — 需要手动将其包裹在BEGIN/COMMIT中,否则可能会发生部分加载。
在批量插入时,能否保证外键的完整性?
可以,前提是遵循加载顺序:首先加载父表,然后加载子表,或者暂时禁用约束。外键错误将回滚整个bulk insert事务。
在加载客户的过程中,包含错误行的文件导致部分加载 — 到一天结束时,数据库和外部源不同步。
优点:
文件经过预先检查错误,Bulk insert被分为5000行的批次,每个批次在其自己的事务中。错误日志保存以供后续分析。
优点: