bcp工具不执行INSERT语句,而是绕过SQL Server查询引擎直接写入数据页,因此比INSERT快数十倍;关键实操点包括:-c/-n/-N格式选择、batch_size与TABLOCK配合、Linux/macOS下分隔符需显式转义、必须使用格式文件(-f)保障长期可复用性。

bcp 工具本身不执行 INSERT 语句,它绕过 SQL Server 的查询引擎直接写入数据页,这才是它比 INSERT 快几十倍的根本原因。 想用 bcp “加速 INSERT”,本质是放弃 INSERT,改用 bcp 导入。下面直击实操关键点。
导出/导入必须匹配数据格式:-c、-n、-N 到底选哪个
选错格式会导致乱码、截断、类型转换失败,反而拖慢整体流程。
-
-c(字符模式)最常用:所有列转为字符串,用-t和-r控制分隔符,兼容性最好,适合跨系统迁移或含文本/日期的混合表 -
-n(本机模式)最快但最脆弱:二进制直传,不经过字符编码转换,要求源表和目标表结构完全一致(包括列顺序、数据类型、NULL 属性),且仅限 SQL Server → SQL Server 场景 -
-N(混合模式)折中方案:数值型列用本机格式,其余列用 Unicode 字符,适合含int/datetime但又有nvarchar的表,避免-w带来的文件体积翻倍
误用 -c 导入 datetime 列却没统一时间格式(如有的是 2026-10-01,有的是 01/10/2026),会触发大量错误并写入 -e 错误日志;而 -n 下哪怕只有一列类型不匹配(比如源是 bigint,目标是 int),整个批次直接失败。
batch_size 和 TABLOCK 是提速双核,但有隐藏约束
-b 控制每批提交行数,-h "TABLOCK" 让 bcp 请求表级锁而非行锁,二者配合能极大减少日志开销和锁竞争。
- 典型值:
-b 10000+-h "TABLOCK",对千万级表效果显著 - 但若目标表有非聚集索引,
TABLOCK会强制重建所有索引——此时速度可能反不如不加TABLOCK、改用-b 5000分批 + 提前DROP INDEX+ 导入后再CREATE INDEX - 如果表启用了
READ_COMMITTED_SNAPSHOT或ALLOW_SNAPSHOT_ISOLATION,TABLOCK可能被忽略,需检查实际执行计划或sys.dm_exec_requests中的wait_type
字段/行终止符在 Linux/macOS 上必须显式转义
Windows 下 -t "," -r "
" 能直接运行,但在 macOS/Linux 的 shell 中,
不会被自动解析为换行符,导致所有数据挤在一行,导入后只剩第一列有值,其余全 NULL。
- 正确写法(任选其一):
-r "\n"、-r $' '、-r " "(用单引号包裹) - 字段分隔符同理:
-t "\t"或-t $' ',尤其当源数据本身含制表符时,必须用-t显式指定,不能依赖默认 - 导出时若用
queryout且 SQL 中含字符串拼接(如CONCAT(a, CHAR(9), b)),导入时却用默认,极易因多层嵌套导致列错位
格式文件(-f)不是可选项,而是长期维护的刚需
bcp 数据文件不含 schema 信息。今天导出的 .dat 文件,半年后表结构微调(比如加一列、改一列长度),再用原命令导入必然失败。
- 首次导出时就加
-f mytable.fmt生成格式文件,后续所有导入都带上-f mytable.fmt - 修改格式文件比重写 bcp 命令快得多:比如跳过新增的计算列,只需把对应行的
0改成0(表示忽略),不用动 SQL 或文件内容 - XML 格式文件(
-x)可读性好,但非 XML 格式文件(默认)体积小、解析快,生产环境建议用非 XML 版本
真正卡住人的往往不是“怎么启动 bcp”,而是“三个月后发现旧数据文件无法复用,又得重新导一遍”。格式文件就是那个被多数人跳过的、但决定能否长期稳定运行的关键一环。

















