导出数据为INSERT语句应手动拼接脚本,不依赖SqlServerCeProvider或SqlClient;需处理identity列(SET IDENTITY_INSERT)、默认值(写DEFAULT)、SQL注入(转义单引号)、分批流式读取防内存溢出,SMO备份仅限DBA场景且需部署运行时依赖。

导出数据为 INSERT 语句:用 SqlServerCeProvider 还是 SqlClient?
直接拼接 INSERT 脚本最稳妥,不依赖数据库驱动类型。SqlServerCe(SQL Server Compact)不支持 SELECT ... INTO 或备份命令,而 SqlClient(SQL Server)虽能执行 BACKUP DATABASE,但需 sysadmin 权限且无法在用户态程序里安全调用——所以“导出为 SQL 脚本”和“数据库备份”本质是两件事,别混用。
实操建议:
- 若目标是生成可执行的
INSERT文本(比如迁移、初始化测试库),自己遍历DataTable或DbDataReader,逐行生成语句,避开 ORM 的延迟加载陷阱 - 若用
SqlConnectionStringBuilder连接 SQL Server,确认连接字符串没带AttachDbFilename——否则你以为连的是远程实例,实际在操作本地 .mdf 文件,导出内容可能错乱 - 字段含单引号、换行符或
NULL时,必须用SqlHelper.EscapeSqlString()或手动.Replace("'", "''"),否则脚本执行报错Incorrect syntax near 'xxx'
生成 INSERT 脚本时怎么处理 identity 列和默认值?
导出脚本若要还原到空表,identity 列不能直接插值,否则报错 Cannot insert explicit value for identity column;但若想保留原 ID(比如做数据归档),又得临时启用 SET IDENTITY_INSERT [table] ON。
实操建议:
- 先查系统视图:
SELECT COLUMN_NAME, IS_NULLABLE, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'xxx',标记出IDENTITY列和有DEFAULT约束的列 - 对 identity 列:默认跳过赋值,只在脚本开头加
SET IDENTITY_INSERT [table] ON,结尾加OFF;如果目标库不允许该语句(如 Azure SQL 逻辑服务器限制),就改用DBCC CHECKIDENT重置种子 - 对有默认值的列(如
GETDATE()、NEWID()),导出时写成DEFAULT字面量,别展开成具体值,否则失去语义
用 SMO 备份数据库:为什么本地能跑,部署后提示“Failed to connect to server”?
SMO(Microsoft.SqlServer.Smo)不是 .NET 内置库,它依赖 SQL Server 客户端运行时(SQL Server Shared Management Objects),而该组件通常只装在装了 SSMS 或 SQL Server 的机器上。生产环境服务器没装,就会在 new Server(connectionString) 这步直接抛 FileNotFoundException。
实操建议:
- 不要把 SMO 当通用备份方案——它本质是 DBA 工具链,适合管理后台,不适合嵌入业务服务
- 若真要用,必须在部署包里附带
Microsoft.SqlServer.ConnectionInfo.dll等 6–8 个 DLL,并确保目标机 .NET Framework 版本 ≥4.6.1(SMO 160+ 要求) - 更轻量的做法是调用命令行:
sqlcmd -S localhost -U sa -P pwd -Q "BACKUP DATABASE [db] TO DISK='d:\b.bak'",但要注意权限隔离和路径写死风险
导出大表时内存爆掉或超时:怎么分批 + 流式写入?
一次性读全量数据进 DataTable,100 万行就可能吃掉 500MB+ 内存;用 SqlDataAdapter.Fill() 默认不设 CommandTimeout,查大表容易卡在 ExecuteReader 报 Timeout expired。
实操建议:
- 用
SqlCommand.ExecuteReader(CommandBehavior.SequentialAccess),配合SqlDataReader.GetValues()按行取值,边读边写文件,内存占用恒定在几 KB - 分页别用
OFFSET/FETCH(SQL Server 2012+),老版本用WHERE id > @lastId ORDER BY id更稳定,避免深分页性能陡降 - 写文件用
StreamWriter并设AutoFlush = true,别等缓冲区满才落盘,否则进程崩溃时最后一段脚本就丢了
identity 列是否导出、默认值要不要固化、SMO 的部署依赖、大结果集的流式边界——这些点不提前判断,脚本生成看着成功,一跑就漏数据或权限失败。










