如何对链接服务器执行存储过程?

Posted

技术标签:

【中文标题】如何对链接服务器执行存储过程?【英文标题】:How to execute a stored procedure against linked server? 【发布时间】:2019-01-23 19:16:40 【问题描述】:

我们目前对链接服务器执行存储过程:

EXECUTE [LinkedServer].[DatabaseName].[dbo].[MyProcedure]

例如:

EXECUTE Screwdriver.CRM.dbo.GetCustomer 619

这很好用;通过链接服务器进行查询工作正常。

禁用已弃用的“远程访问”功能

显然有一个鲜为人知、很少使用的功能,称为远程访问。除了say here:

,微软几乎没有透露这个功能是什么

此配置选项是不推荐使用的 SQL Server 到 SQL Server 通信功能,您可能不应该使用它。

重要

此功能将在 Microsoft SQL Server 的下一版本中删除。不要在新的开发工作中使用此功能,并尽快修改当前使用此功能的应用程序。请改用sp_addlinkedserver。

远程访问选项仅适用于使用sp_addserver 添加的服务器,包含在内是为了向后兼容。

来自 SQL Server 2000 联机丛书:

注意 提供对远程服务器的支持只是为了向后兼容。必须对 SQL Server 的远程实例执行存储过程的新应用程序应该改用链接服务器。

我们只添加了链接服务器,从未使用过此“远程访问”功能,也从未使用sp_addserver添加服务器。

我们都很好。对吧?

除了关闭远程访问会破坏一切

一位审核员提到我们应该关闭远程访问功能:

这是他们剪贴板上的安全复选框 已被 Microsoft 弃用 几乎没用过 我们不使用它

应该没问题吧?

微软文档how to turn off this hardly used feature:

配置远程访问服务器配置选项


EXEC sp_configure 'remote access', 0 ;  
GO  
RECONFIGURE ;  
GO

除非我们这样做:一切都下地狱:

消息 7201,级别 17,状态 4,过程 GetCustomer,第 1 行

无法在远程服务器 'Screwdriver' 上执行过程,因为 SQL Server 未配置为进行远程访问。请您的系统管理员重新配置 SQL Server 以允许远程访问。

比失败更糟糕? 

为了确保我使用的是链接服务器,我:

EXECUTE sp_dropserver @server='screwdriver', @dropLogins='droplogins'

EXECUTE sp_addlinkedserver N'screwdriver', N'SQL Server'

并重新运行我的过程调用:

EXECUTE Screwdriver.CRM.dbo.GetCustomer 619

消息 7201,级别 17,状态 4,过程 GetCustomer,第 1 行 无法在远程服务器“螺丝刀”上执行过程,因为 SQL Server 未配置为进行远程访问。请您的系统管理员重新配置 SQL Server 以允许远程访问。

比失败更糟糕!?

我可以confirm 该服务器链接服务器(而不是“远程”服务器)使用:

SELECT SrvName, IsRemote 
FROM master..sysservers
WHERE SrvName = 'Screwdriver'

Srvname      IsRemote
-----------  --------
screwdriver  0

或者使用现代物品:

SELECT Name, Is_Linked
FROM sys.servers
WHERE Name = 'Screwdriver'

Name         Is_linked
-----------  --------
screwdriver  1

总结

我们现在处于:

我已禁用 远程访问 远程访问仅适用于通过sp_addserver添加的服务器 不适用于通过sp_addlinkedserver添加的服务器 我正在访问通过sp_addlinkedserver 添加的服务器

为什么它不起作用?

这让我想到了我的问题:

如何针对链接的服务器执行存储过程?

还有推论:

如何添加的(即“远程”)服务器执行存储过程

奖金聊天

您使用sp_configure 调整的远程访问 配置选项也通过用户界面公开。 SSMS UI 错误地描述了该功能:

不正确的措辞是:

允许远程连接此服务器

应该这样表述:

允许远程连接 来自此服务器。

Books Online 也错误地记录了该功能:

允许远程连接此服务器

控制运行 SQL Server 实例的远程服务器 执行存储过程。选中此复选框与将 sp_configure remote access 选项设置为 1 的效果相同。清除它会阻止从远程服务器执行存储过程

应该是:

允许远程连接 从此服务器

控制存储过程的执行 运行SQL Server 实例的远程服务器。选中此复选框与将 sp_configure remote access 选项设置为 1 的效果相同。清除它会阻止执行存储过程 from to 一个远程服务器。

现在微软的年轻人不记得他们从未接触过的 20 年前已弃用的功能做了什么,这是有道理的。

来自 BOL 2000 的文档

SQL Server 2000 是最后一次记录此功能。为后代和调试目的在此处复制:

配置远程服务器


远程服务器配置允许连接到一个 Microsoft® SQL Server™ 实例的客户端在另一个 SQL Server 实例上执行存储过程,而无需建立另一个连接。客户端连接的服务器接受客户端请求,并代表客户端将请求发送到远程服务器。远程服务器处理请求并将任何结果返回给原始服务器,原始服务器又将这些结果传递给客户端。

如果您想设置服务器配置以便在另一台服务器上执行存储过程并且没有现有的远程服务器配置,请使用链接服务器而不是远程服务器。存储过程和分布式查询都允许针对链接服务器;但是,对于远程服务器,只允许存储过程。

注意 提供对远程服务器的支持只是为了向后兼容。必须对 SQL Server 的远程实例执行存储过程的新应用程序应该改用链接服务器。

另见

Executing a Stored Procedure on a Linked Server SQL Linked server - Remote access error when executing SP SQL Server Error: Could not execute remote procedure MSDN Blogs: Unable to execute a remote stored procedure over a linked server (archive.is) Configure the remote access Server Configuration Option sp_addlinkedserver (Transact-SQL) sp_configure (Transact-SQL) Security Audit requires turning Remote Access off on all SQL 2005 and SQL 2008 Servers

替代标题:禁用 SQL Server 远程访问会中断存储过程。

【问题讨论】:

我投票决定将其移至 dba.stackexchange.com,因为您更有可能从坐在该交易所几乎完全恕我直言的人们那里得到正确答案。 以下查询的结果是什么?:SELECT * FROM [Screwdriver].sys.configurations WHERE name = 'remote access' @SlavaMurygin Invalid object name 'screwdriver.sys.configurations'. 但如果您对目标服务器上sys.configurations 表中的remote access 设置感兴趣:它已打开(值=1) 【参考方案1】:

好吧,当你是对的时候,你就是对的,不管它是否被记录在案。将remote access 设置为0(并重新启动)会导致使用四部分语法的远程存储过程调用失败,即使所有文档都建议链接服务器不应该失败。即使在最新版本的 SQL Server 2017 (RTM CU12) 上也是如此,因此这不是特定于版本的。目前尚不清楚这是否是一个真正的限制,或者代码是否只是错误并基于remote access 功能检查阻止它,即使它在技术上可以工作。

涉及四部分名称 (SELECT * FROM server.db.scheme.table) 的查询不会失败,大概是因为这仅适用于链接服务器,并且从一开始就不会涉及远程访问。

作为一种解决方法,您可以将调用更改为使用EXECUTE .. AT

EXEC ('EXECUTE CRM.dbo.GetCustomer 619') AT Screwdriver

只要链接服务器启用了RPC Out 选项(如果由sp_addlinkedserver 添加且没有特殊选项,则默认为该选项)。

不幸的是EXECUTE .. AT在涉及参数时就不太方便了,因为它只支持?语法:

EXEC ('EXECUTE CRM.dbo.GetCustomer @Customer=?', 619) AT Screwdriver

参数名称在这里是可选的,但我强烈建议使用它来保持可预测性。与EXECUTE 相同——它是可选的,但它清楚地表明我们实际上是在运行任意查询,而不仅仅是调用存储过程。

如果你的程序有OUTPUT 参数,这个plain 将不起作用; EXECUTE .. AT 不够聪明。您可以在调用中指定OUTPUT,但该值不会被复制回来。解决方法超出了此答案的范围,但它们不会很漂亮。

为此打开suggestion 可能是值得的,因为这似乎是真正应该按照文档说明工作的东西(如果微软想要永久摆脱remote access,他们需要无论如何)。

【讨论】:

【参考方案2】:

我已经在 2016 和 2019 版本的 SQL Server 上测试过,效果很好。您可以从配置中禁用远程访问,并且您将能够在链接服务器上执行该过程。只需在 Linked server 的参数中开启 RPC out 选项即可。

【讨论】:

以上是关于如何对链接服务器执行存储过程?的主要内容,如果未能解决你的问题,请参考以下文章

执行使用 PyMSSQL 引用链接服务器的存储过程时出错

SQLSERVER 链接服务器执行存储过程

SQL使用链接服务器执行远程数据库上的存储过程

如何在 DACPAC 部署中仅部署一组选定的存储过程?

sqlserver 链接服务器调用存储过程

链接服务器对查询的影响