凌峰创科服务平台

SQL Server跨服务器查询如何实现?

核心概念

跨服务器查询,就是在一个 SQL Server 实例(我们称之为“本地服务器”或“源服务器”)中,去查询另一个 SQL Server 实例(我们称之为“远程服务器”或“目标服务器”)上的数据库对象。

SQL Server跨服务器查询如何实现?-图1
(图片来源网络,侵删)

使用链接服务器

这是最常用、最灵活、功能最强大的方法,链接服务器是在本地 SQL Server 实例中配置的一个已注册的远程数据源,一旦配置好,你就可以像查询本地表一样,使用四部分名称来查询远程服务器上的对象。

工作原理

本地服务器会通过 OLE DB 或 ODBC 驱动程序与远程服务器建立连接,然后将你的查询请求发送到远程服务器执行,最后将结果返回给本地服务器。

优点

  • 功能全面:支持几乎所有 T-SQL 语句,包括 SELECT, INSERT, UPDATE, DELETE,甚至分布式事务。
  • 语法直观:使用四部分名称 [服务器名].[数据库名].[架构名].[对象名],非常容易理解。
  • 性能优化:可以配置链接服务器使用特定的驱动程序(如 SQLNCLI)以获得更好的性能。
  • 支持分布式查询:可以在一个查询中同时连接本地和远程多个表进行 JOIN 操作。

缺点

  • 配置复杂:需要预先在本地服务器上进行配置,需要一定的权限。
  • 权限管理:需要确保本地服务器的登录账户在远程服务器上有相应的访问权限。
  • 网络依赖:对网络稳定性和延迟比较敏感。

使用 OPENDATASOURCE 和 OPENROWSET 函数

这两种方法提供了一种无需预先配置链接服务器的方式,可以直接在 SQL 语句中指定连接信息来访问远程数据,它们通常用于临时性、一次性的查询任务。

工作原理

这两个函数都是“一次性”的连接器,每次执行包含它们的 SQL 语句时,都会建立一个新的连接到远程服务器,执行查询,然后关闭连接。

SQL Server跨服务器查询如何实现?-图2
(图片来源网络,侵删)

优点

  • 无需预配置:无需在本地服务器上创建链接服务器,非常方便。
  • 灵活性高:适合在脚本、存储过程或临时查询中动态指定服务器信息。

缺点

  • 安全性差:连接字符串(尤其是密码)可能会以明文形式出现在代码中,存在安全风险,虽然可以使用 WITH CREDENTIAL 来部分缓解,但管理起来仍然复杂。
  • 性能差:每次查询都建立新连接,开销巨大,不适合高频查询。
  • 功能受限:在视图、存储过程、函数等对象内部使用时有限制。OPENDATASOURCEOPENROWSET 通常只允许出现在 SELECTINSERTUPDATEDELETE 语句的 FROM 子句中。
  • 连接池无效:无法利用连接池,资源消耗大。

使用分布式事务

当你需要对多个服务器上的数据进行原子操作(即所有操作都成功,或所有操作都失败回滚)时,就需要使用分布式事务。

工作原理

它依赖于 Microsoft 分布式事务处理协调器,所有参与事务的服务器都必须被配置为支持分布式事务(通常是通过启用 MSDTC 服务)。

优点

  • 数据一致性:保证了跨服务器操作的原子性,是维护数据一致性的利器。

缺点

  • 配置复杂:需要在本地服务器和所有远程服务器上都正确配置 MSDTC,并且网络防火墙需要开放特定端口(通常是 135 端口和动态端口)。
  • 性能开销大MSDTC 协调事务会带来额外的性能开销。
  • 故障点增多:引入了 MSDTC 这个外部组件,增加了系统的复杂性,可能成为新的故障点。

使用应用程序层连接

这是最现代、最推荐用于应用开发的模式,将数据聚合和逻辑处理放在应用程序层完成。

工作原理

  1. 你的应用程序(如 C#、Java、Python 应用)建立到两个(或多个)SQL Server 数据库的独立连接。
  2. 应用程序从源服务器 A 查询数据。
  3. 应用程序从目标服务器 B 查询数据。
  4. 在应用程序内存中,使用代码逻辑(如 LINQ, Pandas, Java Streams)对来自不同数据源的结果进行 JOIN、聚合和转换。
  5. 最后将处理结果写入目标表或返回给用户。

优点

  • 架构清晰:数据库只负责数据存储和查询,业务逻辑在应用层处理,符合单一职责原则。
  • 性能最佳:可以针对每个查询进行优化,避免在数据库之间传输大量中间数据。
  • 灵活性高:可以轻松地连接不同类型的数据源(不仅仅是 SQL Server)。
  • 解耦:数据库服务器之间没有直接的依赖关系。

缺点

  • 开发复杂度:需要在应用程序中编写更多的数据处理逻辑。
  • 网络往返:可能需要多次网络往返来获取数据,如果设计不当,性能可能不如数据库端的 JOIN

详细示例:使用链接服务器

假设我们有两台服务器:

SQL Server跨服务器查询如何实现?-图3
(图片来源网络,侵删)
  • 本地服务器: SERVER_A
  • 远程服务器: SERVER_B

我们想在 SERVER_A 上查询 SERVER_BSalesDB 数据库中的 Orders 表。

步骤 1: 在本地服务器上创建链接服务器

SERVER_A 上以管理员身份执行以下 T-SQL 语句。

-- 使用 sp_addlinkedserver 创建链接服务器
EXEC master.dbo.sp_addlinkedserver
    @server = N'SERVER_B_LINK', -- 给链接服务器起一个你喜欢的别名
    @srvproduct = N'SQL Server';
-- 使用 sp_addlinkedsrvlogin 配置登录映射
-- 这里的 'sa' 和 'your_strong_password' 是 SERVER_B 上的登录名和密码
-- 你也可以使用 'true' 来使用本地服务器的登录上下文(需要远程服务器信任本地服务器)
EXEC master.dbo.sp_addlinkedsrvlogin
    @rmtsrvname = N'SERVER_B_LINK',
    @useself = 'false',
    @locallogin = NULL, -- 表示所有本地登录都使用此映射
    @rmtuser = N'sa',
    @rmtpassword = N'your_strong_password';

步骤 2: 执行跨服务器查询

链接服务器创建成功后,你就可以使用它了。

示例 1: 简单查询

-- 使用四部分名称进行查询
SELECT *
FROM [SERVER_B_LINK].[SalesDB].[dbo].[Orders]
WHERE OrderDate > '2025-01-01';
  • [SERVER_B_LINK]: 你在步骤 1 中创建的链接服务器别名。
  • [SalesDB]: 远程服务器上的数据库名。
  • [dbo]: 远程表所在的架构名。
  • [Orders]: 远程表的名称。

示例 2: 与本地表进行 JOIN

-- 假设 SERVER_A 上有一个 Customers 表
SELECT A.CustomerName, B.OrderID, B.OrderDate
FROM [SERVER_A].[YourLocalDB].[dbo].[Customers] AS A
INNER JOIN [SERVER_B_LINK].[SalesDB].[dbo].[Orders] AS B ON A.CustomerID = B.CustomerID
WHERE B.OrderDate BETWEEN '2025-01-01' AND '2025-12-31';

步骤 3: (可选) 删除链接服务器

如果不再需要链接服务器,可以将其删除。

EXEC master.dbo.sp_dropserver
    @server = N'SERVER_B_LINK',
    @droplogins = 'droplogins'; -- 同时删除关联的登录映射

总结与选择建议

方法 优点 缺点 适用场景
链接服务器 功能强大、语法直观、支持分布式查询 需要预配置、权限管理复杂 首选方案,适用于需要频繁、稳定地进行跨服务器查询的场景,特别是需要 JOIN 操作时。
OPENDATASOURCE/OPENROWSET 无需预配置、灵活 安全性差、性能差、功能受限 临时性、一次性查询,快速从另一台服务器导少量数据,或在不允许创建链接服务器的环境中。
分布式事务 保证数据一致性 配置复杂、性能开销大、故障点多 必须保证原子性的业务场景,从一个账户扣款并同时向另一个账户存款,涉及两个不同的数据库。
应用层连接 架构清晰、性能最佳、解耦 开发复杂度高 现代应用开发推荐,将业务逻辑与数据访问分离,适合微服务架构或需要连接多种数据源的系统。
分享:
扫描分享到社交APP
上一篇
下一篇