sql跨服务器查询,服务说白了就是器查在一台数据库服务器上,直接去查另一台服务器上的询语表。这事儿听着简单,服务真做起来坑不少。器查我见过不少开发第一次搞这个,询语上来就写
select * from [192.168.1.100].mydb.dbo.users,服务结果报错“找不到服务器”。器查为啥?询语因为你得先把对方“注册”过来,用sp_addlinkedserver。服务比如你本机是器查A服务器,想查B服务器上的询语数据。第一步,服务在A上执行:
EXEC sp_addlinkedserver @server = 'RemoteServer',器查 -- 随便起个名字 @srvproduct = '', @provider = 'SQLOLEDB', @datasrc = '192.168.1.100' -- B的IP或主机名然后配登录名映射,不然没权限:
EXEC sp_addlinkedsrvlogin @rmtsrvname = 'RemoteServer',询语 @useself = 'false', @locallogin = NULL, @rmtuser = 'sa', @rmtpassword = '你的密码'做完这两步,就能查了:
SELECT * FROM RemoteServer.mydb.dbo.users注意四段式:链接服务器名.数据库名.架构名.表名。少一段都不行。
但这里有个很隐蔽的问题——性能。跨服务器查询,如果只是拉小表数据还好,比如每天同步几百条配置。可你要是拿它做关联查询,比如A服务器的订单表join B服务器的用户表,那速度能慢到你怀疑人生。原因很简单:SQL Server会把B表的数据一条条拉过来,然后本地做hash match。数据量一大,网络带宽就成了瓶颈。我遇到过一次,两张百万级表关联,查询跑了20分钟没出来,最后直接kill了。
所以有经验的DBA会建议:能不跨服务器join就别join。实在要查,先把远端表的数据拉到本地临时表,再本地关联。比如:
SELECT * INTO #tempUsers FROM RemoteServer.mydb.dbo.users WHERE last_login > '2024-01-01' -- 然后本地join #tempUsers这样至少网络传输只发生一次,而且你还能在临时表上加索引,速度提升不是一点半点。
还有一种情况,你想在A服务器上直接执行B服务器的存储过程,或者往B服务器写数据。这时候用
OPENQUERY更顺手。它把整个查询发给远端执行,只返回结果,不拉表结构。比如:SELECT * FROM OPENQUERY(RemoteServer, 'SELECT id, name FROM mydb.dbo.users WHERE age > 30')这个写法有个好处——远端先过滤,只传结果回来,传输量小。但坏处是字符串拼接容易出错,尤其是里面带引号的时候,双层单引号能把你逼疯。我一般写动态SQL时才用它,静态查询直接四段式更清晰。
还有一类坑,叫“分布式事务”。你要是跨服务器做update或insert,SQL Server默认会启动MSDTC(分布式事务协调器)。这玩意儿配置麻烦,防火墙一挡就报错。比如你执行:
INSERT INTO RemoteServer.mydb.dbo.logs (msg) VALUES ('hello')如果两边服务器不在同一个域,或者MSDTC没开启,直接报“该操作已超过超时时间”。解决办法倒简单——把
SET REMOTE_PROC_TRANSACTIONS OFF,关掉分布式事务要求,让它各自提交。但代价是数据一致性没保障,中间断了可能一边成功一边失败。你自己权衡。最后说个我踩过的真实案例。之前有个项目,生产库在A,报表库在B,每天凌晨要同步订单数据。一开始用跨服务器查询直接insert,跑了三个月都没事。结果某天B服务器重启,网络闪断,同步任务挂了,而且因为没做错误处理,数据缺了当天一整天的。后来我改成用SQL Agent作业,先把A的数据导出到文件,再B那边bulk insert。虽然多一步,但稳定多了。
所以你看,跨服务器查询不是不能玩,但得清楚边界。小数据量、低频查询、网络好,随便用。大数据量、高频同步、网络不稳——还是老老实实走ETL流程吧。工具本身没毛病,用错场景才是问题。
顶: 54221踩: 5157






评论专区