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

时间:2019-01-23 19:16:40

标签: sql-server sql-server-2008-r2

我们当前使用以下方法对链接服务器执行存储过程:

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

例如:

EXECUTE Screwdriver.CRM.dbo.GetCustomer 619

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

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

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

之外,Microsoft关于此功能几乎没有话要说。
  

此配置选项是SQL Server到SQL Server的一种模糊的通信功能,已被弃用,您可能不应该使用它。

     

重要

     

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

     

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

并且从SQL Server 2000联机丛书中:

  

enter image description here 注意仅出于向后兼容的目的提供了对远程服务器的支持。必须针对SQL Server的远程实例执行存储过程的新应用程序应改用链接服务器。

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

我们都很好。对吧?

除关闭远程访问外,其他所有操作均会

审计人员提到我们应该关闭远程访问功能:

  • 这是他们剪贴板上的安全复选框
  • 它已被Microsoft弃用
  • 很少使用
  • 我们不使用它

应该没事吧?

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行
  无法在远程服务器“ Screwdriver”上执行过程,因为未将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用户界面错误地描述了该功能:

enter image description here

  • 其用语是::允许到该服务器的远程连接
  • 应为允许从该服务器 的远程连接。

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

  

允许与此服务器的远程连接

     

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

应该是:

  

允许远程连接 从该服务器

     

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

这是有道理的,这些天微软的年轻人不记得他们从未碰过的20岁弃用的功能是什么。

BOL 2000的文档

SQL Server 2000是最后一次记录此功能。转载于此,供后代和调试之用:

  

配置远程服务器

     

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

     

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

     

enter image description here 注意仅出于向后兼容的目的提供了对远程服务器的支持。必须针对SQL Server的远程实例执行存储过程的新应用程序应改用链接服务器。

另请参见

备用标题:禁用SQL Server远程访问会破坏存储过程。

2 个答案:

答案 0 :(得分:1)

好吧,只要您是对的,就对了,无论是否已记录在案。将remote access设置为0(并重新启动)会导致使用四部分语法的远程存储过程调用失败,即使所有文档都表明链接服务器不应失败。即使在最新版本的SQL Server 2017(RTM CU12)上也是如此,因此这不是特定于版本的。尚不清楚这是否是 real 限制,还是代码只是错误的并基于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参数,则此普通格式将不起作用; EXECUTE .. AT不够聪明。您可以在呼叫中指定OUTPUT,但不会将值复制回去。解决方法超出了此答案的范围,但效果并不理想。

为此,可能值得打开suggestion,因为这似乎确实应该按文献记载进行操作(并且,如果Microsoft希望永久摆脱remote access,他们会仍然需要)。

答案 1 :(得分:0)

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