高效批量插入必须绕过常规insert路径,优先选用bulk insert(需tablock、bulk_logged恢复模式、服务账户文件权限)或sqlbulkcopy(需batchsize、列映射、enablestreaming),中小量可分批多值insert并禁用非聚集索引。

直接用 INSERT INTO ... VALUES (), () 插几千行,性能会断崖式下跌;SQL Server 2022 真正高效批量插入,必须绕开常规语句路径,选对工具、关对选项、配对环境。
BULK INSERT 从本地或 UNC 文件导入(最快,但路径权限要卡死)
这是 SQL Server 原生最快的方式,数据不走网络协议栈,SQL Server 进程直接读文件。但关键限制是:文件路径必须对 SQL Server 服务账户可见 —— 不能填你本地电脑的 C:dataorders.csv,得是服务器本地路径(如 D:importusers.txt)或 UNC 路径(如 \fileservershareusers.csv),且服务账户要有读取权限。
-
TABLOCK必须加,否则默认行锁会让并发写入变成排队写入,速度掉 70% 以上 - 恢复模式建议临时切为
BULK_LOGGED:ALTER DATABASE yourdb SET RECOVERY BULK_LOGGED,导入完再切回FULL,否则日志全量记录,磁盘 I/O 暴涨 - SQL Server 2017+ 支持
FORMAT = 'CSV',比手动写FIELDTERMINATOR更健壮(自动处理引号、换行符),但必须显式指定FIRSTROW = 2跳过表头 - 字段类型必须严格匹配目标列,比如 CSV 里写
"2026-08-13",而目标列是datetime2就行,但写成"Aug 13 2026"会整批失败,错误只报“批量加载失败”,不提示哪一行哪一列
SqlBulkCopy 从 .NET 应用推送(最灵活,日常首选)
当你数据在内存里(DataTable、DataReader)、或文件在客户端机器上、或需要动态生成数据时,SqlBulkCopy 是唯一能接近 BULK INSERT 性能的选择。
- 必须设
BatchSize(如5000),否则默认一次性提交全部行,容易触发事务日志撑爆或OutOfMemoryException - 源列顺序和目标表不一致?必须显式映射:
bulkCopy.ColumnMappings.Add("src_name", "dest_col"),漏一条就报错 - 大数据流推荐开启
EnableStreaming = true,但前提是源实现了IDataReader(比如SqlDataReader或自定义流式 reader),否则无效 - 别在
WriteToServer外包SqlTransaction——SqlBulkCopy内部已用最小日志模式,加外部事务反而扩大锁范围、拖慢速度
多值 INSERT + 分批事务(中小数据量,无额外权限要求)
当只有几百到几千行、没权限改恢复模式、也没法用 BULK INSERT 或 SqlBulkCopy 时,这条路最稳妥,但要注意分批粒度。
- 单条
INSERT INTO t(a,b) VALUES (1,'x'),(2,'y'),...,(5000,'z')最多塞 1000 行左右,再多 SQL Server 会报Internal error: An expression services limit has been reached - 建议按每批 500–1000 行拆分,用显式事务包裹:
BEGIN TRAN; INSERT ...; COMMIT TRAN;,避免单条失败导致全滚 - 目标表有非聚集索引?插入前用
ALTER INDEX ... DISABLE,插完再REBUILD,比边插边维护索引快 3–5 倍 - 如果列允许 NULL,但 CSV 或源数据里是空字符串,记得加
KEEPNULLS选项(BULK INSERT)或在应用层转成null(SqlBulkCopy),否则空字符串会被当成实际值插入
真正卡住性能的往往不是语法,而是恢复模式、索引状态、服务账户文件权限这三处;很多人调了一晚上 BULK INSERT 语句,最后发现只是忘了加 TABLOCK 或没切 BULK_LOGGED。先确认这三项,再调其他参数。










