如何重写此存储过程以不使用游标?

Vor*_*ter -1 sql-server stored-procedures t-sql

我想更改我的存储过程,使其不再使用游标来运行。我怎样才能更好地编写这个存储过程?

我正在使用游标编译动态 SQL 以查询我从列表中创建的服务器,以跟踪事务日志备份历史记录。

ALTER PROC [dbo].[spLogBackup]

AS

TRUNCATE TABLE dbo.tLogBackup

DECLARE servers_cursor CURSOR
FOR
select  distinct LinkedserverName
from dbo.Environment
join master..sysservers on srvname COLLATE DATABASE_DEFAULT  = LinkedserverName COLLATE DATABASE_DEFAULT
where LinkedServerName not in ('TestDB')

and ServerUse in ('PROD', 'DR')
and IncludeInstats = 1
order by LinkedServerName

OPEN servers_cursor
DECLARE @Servername varchar(250)

DECLARE @sql varchar(8000)

FETCH NEXT FROM servers_cursor INTO @ServerName
WHILE (@@FETCH_STATUS = 0)
BEGIN
    --Looping throught the servers.
    set @sql = 'insert into dbo.tLogBackup (servername, rundate, runtime, jobname, Status, CurrentStatus, enabled) select ''' + @ServerName + ''',last_run_date, last_run_time, name, last_run_outcome, current_execution_status, enabled
     from openquery([' + @ServerName + '],''exec msdb.dbo.sp_get_composite_job_info'' )'
    print @ServerName
    exec (@sql)
    --SELECT (@sql)
  FETCH NEXT FROM servers_cursor INTO @ServerName
END
CLOSE servers_cursor
DEALLOCATE servers_cursor
Run Code Online (Sandbox Code Playgroud)

RDF*_*ozz 5

游标经常被谴责,而且通常是正确的。SQL 在处理一些所谓的“包”数据时往往效果最好;游标适合逐行处理。如果您可以重写当前在 SQL 中使用逐行处理的内容,以便通过一次查询运行来处理所有内容,那么它几乎总是会提高性能。

但是,在这种情况下,您的光标正在识别多个远程服务器,因此它可以向这些服务器中的每一个发送请求。没有办法(据我所知)一次向多个链接服务器发送请求。因此,通常反对游标的论点在这里并不适用。

可能有更快的方法来获得您想要的东西(例如,使用 SSIS 包从各种其他服务器中提取数据,您可以在其中并行地从多个服务器中提取数据),在这里使用游标没有任何问题,从功能上讲,任何方法都可能使用相同的机制。