SQL Server里用链接服务器做INSERT,接服最坑人的接服不是语法,是接服那些藏在细节里的性能陷阱和权限暗坑。我见过太多人把远程表当本地表使,接服一条INSERT丢过去,接服等半天没反应,接服最后发现是接服网络往返把性能吃光了。
链接服务器的接服INSERT本质上是分布式查询。SQL Server把语句发给远程机,接服远程机执行完再把影响行数传回来。接服这中间每行数据都要经过TDS协议打包、接服传输、接服解包。接服你要是接服写个INSERT INTO LinkedServer.DB.dbo.Table SELECT ...,本地查出来的接服十万行数据得一行行塞到管道里,慢得让人抓狂。
有个真实案例。去年帮朋友调一个跨库同步的存储过程,他们用链接服务器从生产库往报表库灌数据,每晚跑一个多小时。我看了一眼代码,循环里逐条INSERT,每条都带个事务。这种写法等于让远程服务器陪着你做一万次握手。改成INSERT ... SELECT * FROM OPENQUERY(LinkedServer, 'SELECT ...')以后,直接把查询下推给远程机执行,数据以流式方式返回,跑完只要六分钟。差十倍不止。
说到OPENQUERY,这才是链接服务器INSERT的正确打开方式。它把整个查询字符串发给远程服务器,由远程优化器生成执行计划。相比之下,四段式命名INSERT INTO [server].[db].[schema].[table]是本地先解析,再把逐行数据推过去,远程服务器根本没有优化空间。能用OPENQUERY就别用四段式,这是铁律。
权限问题更隐蔽。链接服务器映射的登录账号如果只给了远程表的INSERT权限,你执行INSERT INTO ... SELECT时,本地查询的源表权限也得检查。有时候报错信息模模糊糊,说什么"无法处理该对象",其实是因为链接服务器配置里用了模拟登录,但本地账号没权限访问远程的某些系统视图。遇到这种问题,先查sys.servers里的data_access选项,再确认sp_addlinkedsrvlogin的映射是否正确。
还有个没人提的坑:事务日志。链接服务器INSERT默认是分布式事务,如果远程操作失败,本地会尝试回滚。但分布式事务协调器(MSDTC)没配置好的话,这条INSERT会直接报错"事务管理器不可用"。你猜怎么着?很多人第一反应是重装驱动,其实只要在两边服务器上开启网络DTC访问就行。这个坑我踩过两次,每次都是查了半天才发现是DTC没开。
写链接服务器INSERT的时候,记住一个原则:能下推就下推。别在本地做任何聚合或者计算再传给远程,让远程自己处理。比如你要把本地表A的数据插入远程表B,但A里有些字段需要转换,那就写INSERT INTO ... SELECT * FROM OPENQUERY(..., 'SELECT col1, CONVERT(varchar(10), col2, 120) FROM A')——虽然A在本地,但转换逻辑放在远程执行,反而减少了本地到远程的数据传输量。
最后说个冷门细节。链接服务器的名称如果带特殊字符,比如连字符或者点号,四段式命名必须用方括号括起来,但OPENQUERY的第一个参数是字符串,不用加括号。很多人在这里栽跟头,报错"语法错误"还以为是SQL写错了。实际上就是链接服务器名字没处理好。
干这行久了你会明白,链接服务器就是个远程代理,你用得好,它帮你省事;用不好,它帮你添堵。INSERT只是最基础的用法,但能把基础用法吃透的人,已经能解决80%的跨库写入问题了。