同服务器不同实例必须用 Linked Server;因SQL Server不识别实例名作为服务器标识,需通过sp_addlinkedserver注册链接服务器,指定正确provider(如MSOLEDBSQL)和datasrc(网络地址),并配套配置登录映射与rpc out选项,Azure SQL托管实例则不支持该机制。

同服务器不同实例必须用 Linked Server
同一台物理机上装了 SQL2019 和 SQL2022 两个独立实例,想在 SQL2019 的存储过程中查 SQL2022 里的 DB_A.dbo.Users?直接写四段式名称(如 SQL2022.DB_A.dbo.Users)会报错 Could not find server 'SQL2022' in sys.servers。因为 SQL Server 不认“实例名”作为服务器标识,只认 sys.servers 里注册的链接服务器名。
创建 Linked Server 要指定正确的 provider 和 datasrc
用 sp_addlinkedserver 时容易填错参数,尤其 @provider 和 @datasrc:
-
@provider推荐用'SQLNCLI11'或'MSOLEDBSQL'(SQL Server 2016+),避免用已废弃的'SQLOLEDB' -
@datasrc填远程实例的**网络可访问地址**,不是本地实例名;比如'192.168.1.100\SQL2022'或'server-name\SQL2022',端口需显式加在后面(如'192.168.1.100,14333') - 必须配套调用
sp_addlinkedsrvlogin显式映射登录,不能依赖@useself = 'true'(Windows 身份跨实例常失败) - 若要在存储过程中执行远程存储过程,还得开
rpc out:EXEC sp_serveroption 'RemoteSQL2022', 'rpc out', 'true'
存储过程中引用远程表的写法和性能陷阱
在存储过程里用 Linked Server 查远程表,表面写法简单,但实际执行逻辑和本地 JOIN 完全不同:
- 写法就是标准四段式:
SELECT u.Name FROM RemoteSQL2022.DB_A.dbo.Users u,别漏掉dbo架构名 - SQL Server 默认把整个远程表拉到本地再过滤,除非用
OPENQUERY把 WHERE 条件下推到远端执行 - 远程列参与 JOIN 或 WHERE 时,如果没建索引或数据量大,可能触发全表扫描 + 网络传输瓶颈
- 错误示例:
WHERE u.ID = @local_id—— 这个变量不会下推,远程端看到的是无条件 SELECT - 更安全的写法:
SELECT * FROM OPENQUERY(RemoteSQL2022, 'SELECT Name FROM DB_A.dbo.Users WHERE ID = 123')
Azure SQL 托管实例不支持 Linked Server
如果你的“远程实例”其实是 Azure SQL 托管实例(Azure SQL MI),sp_addlinkedserver 会直接报错 Ad hoc access to OLE DB provider 'SQLNCLI11' has been denied。这是硬性限制,截至 2026 年 6 月仍不支持 Linked Server。
替代方案只有两个:
- 应用层聚合:把查询拆成两步,在应用代码里分别查本地和托管实例,内存中合并
- 数据同步:用 Azure Data Factory 或 Change Tracking + 预置表,把远程数据定期同步到本地库
别试图用 OPENDATASOURCE 或 OPENROWSET 绕过——它们在托管实例上同样被禁用,且需要启用 Ad Hoc Distributed Queries,而该选项在 Azure 环境不可配置。

















