bcp (Bulk Copy Program) 是 SQL Server 原生高性能批量導入導出工具,通過 xp_cmdshell 封裝為存儲過程可實現定時自動化備份/歸檔。本文提供生產級存儲過程模板,詳解授權、參數、亂碼、路徑、服務實例名等實戰坑點。
EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;
-- 生產環境建議:用完即關閉,或封裝於簽名存儲過程中臨時開啟
-- 導出查詢結果到文件
bcp "SELECT * FROM db.dbo.table" queryout "D:\export.txt" -c -S "Server\Instance" -U user -P pwd
-- 導入文件到表
bcp db.dbo.table in "D:\import.txt" -c -S "Server\Instance" -U user -P pwd
-- 關鍵參數
-c 字符模式 (默認製表符分隔、換行符結束),適合文本查看
-w 原生 Unicode 模式 (雙字節字符前綴長度),解決中文亂碼,文件較大
-n 原生數據庫類型 (二進制),最高性能,跨版本不可移植
-t 自定義字段分隔符 (如 -t,)
-r 自定義行分隔符 (如 -r\n)
-q 啟用帶引號標識符 (含特殊字符表名/列名)
-k 保留空值 (不轉為默認值)
-E 保留標識列值 (IDENTITY)
-h 提示 (如 TABLOCK, CHECK_CONSTRAINTS, ORDER(...))
CREATE PROCEDURE dbo.sp_Export_History_Data
@FilePath VARCHAR(200) = 'D:\BCP_Export\' -- 必須以 \ 結尾,SQL 服務賬號需寫入權限
AS
BEGIN
SET NOCOUNT ON;
DECLARE @TableName SYSNAME, @SQL NVARCHAR(MAX), @Cmd NVARCHAR(MAX), @FileName VARCHAR(200);
DECLARE @ServerInstance VARCHAR(100) = @@SERVERNAME; -- 自動獲取實例名
DECLARE @DBName SYSNAME = DB_NAME();
DECLARE @User VARCHAR(100) = 'bcp_user'; -- 專用低權限賬號
DECLARE @Pwd VARCHAR(100) = 'StrongPwd@2024';
-- 目標表游標 (通配符篩選)
DECLARE cur CURSOR LOCAL FAST_FORWARD FOR
SELECT name FROM sys.tables
WHERE name LIKE 'WM_ORDER%' OR name LIKE 'WM_PICKING%' OR name LIKE 'RP_%';
OPEN cur;
FETCH NEXT FROM cur INTO @TableName;
WHILE @@FETCH_STATUS = 0
BEGIN
-- 動態查詢:僅導出 MODIFY_TIME > 10 個月前的數據
SET @SQL = N'SELECT * FROM ' + QUOTENAME(@DBName) + N'.dbo.' + QUOTENAME(@TableName)
+ N' WHERE DATEDIFF(MONTH, MODIFY_TIME, GETDATE()) > 10';
-- 文件名:表名_YYYYMMDD.txt
SET @FileName = @TableName + '_' + CONVERT(VARCHAR(8), GETDATE(), 112) + '.txt';
SET @FileName = @FilePath + @FileName;
-- BCP 命令組裝 (使用 -w 解決中文亂碼)
SET @Cmd = 'bcp "' + @SQL + '" queryout "' + @FileName + '" -w -S "' + @ServerInstance + '" -U "' + @User + '" -P "' + @Pwd + '"';
PRINT 'Exporting: ' + @TableName + ' -> ' + @FileName;
-- PRINT @Cmd; -- 調試時開啟
EXEC master..xp_cmdshell @Cmd, NO_OUTPUT; -- NO_OUTPUT 抑制命令行輸出
FETCH NEXT FROM cur INTO @TableName;
END
CLOSE cur; DEALLOCATE cur;
END;
GO
-- 執行測試
EXEC dbo.sp_Export_History_Data 'D:\BCP_Export\';
| 坑點 | 現象 | 根因 | 解決 |
|---|---|---|---|
| 中文亂碼 | 導出文件中文變亂碼/問號 | 默認 -c 使用代碼頁 (ACP),多實例/跨機器代碼頁不一致 | 統一使用 -w (Unicode),文件雙字節前綴長度,完美保留中文 |
| SQLState=S1000 NativeError=0 | 導出失敗,提示語法錯誤 | 數據庫/表名拼寫錯誤、未加引號、特殊字符 | 使用 QUOTENAME() 包裹標識符,PRINT @Cmd 複製到 CMD 手工驗證 |
| SQLState=S0002 NativeError=208 | 導入/導出失敗,找不到服務器 | -S 參數錯誤:缺少實例名、IP/主機名錯誤 | -S "IP\InstanceName" 或 -S "HostName\InstanceName",參考 SSMS 連接屬性 |
| 文件寫入失敗/權限拒絕 | xp_cmdshell 返回「存取被拒絕」 | SQL 服務啟動賬號無目標目錄寫入權限 | 目標目錄授權 SQL 服務賬號 (或代理賬號) Modify 權限;或用網絡共享 + 域賬號 |
| 導出文件過大/超時 | 單表億級數據導出極慢、磁盤滿 | 單線程、無分區、無壓縮 | 分區表按分區導出、並行多進程、管道輸出 gzip 壓縮、或改用 BACKUP DATABASE 物理備份 |
Start-Job / SQL Agent 多步驟並行啟動多個表導出。MODIFY_TIME / 主鍵,下次僅導出增量 (CDC/Change Tracking 配合更佳)。bcp ... queryout - | az storage blob upload ... 管道流式上傳 Azure Blob/S3,無本地落盤。BCP 以「原生、高速、可腳本化」三大特性,成為 SQL Server 大數據搬運的基石工具。封裝為參數化存儲過程、統一 Unicode 模式、權限最小化、元數據驅動,即可構建企業級自動化數據歸檔管道。