是否可以优化或重写此光标以获得最佳性能?

时间:2012-02-08 16:49:25

标签: sql-server database tsql cursor

需要更新我们服务器上的所有数据库,并在每个数据库上执行相同的逻辑。有问题的数据库都遵循一个通用的命名方案,如CorpDB1,CorpDB2等。而不是为每个有问题的数据库(超过50个)创建一个SQL代理作业,我考虑过使用游标迭代数据库列表然后在每个上执行一些动态sql。鉴于游标应该是最后手段的普遍观念;是否可以通过使用未记录的sp_MSforeachdb stored procedure来重写以获得更好的性能或以其他方式编写?

DECLARE @db VARCHAR(100) --current database name
DECLARE @sql VARCHAR(1000) --t-sql used for processing on each database

DECLARE db_cursor CURSOR FAST_FORWARD FOR
    SELECT name
    FROM MASTER.dbo.sysdatabases
    WHERE name LIKE 'CorpDB%'
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @db
WHILE @@FETCH_STATUS = 0
BEGIN
    SET @sql = 'USE ' + @db +
    ' DELETE FROM db_table --more t-sql processing'
    EXEC(@sql)
    FETCH NEXT FROM db_cursor INTO @db
END
CLOSE db_cursor
DEALLOCATE db_cursor

2 个答案:

答案 0 :(得分:5)

当游标用于处理基于集合的过程代码问题时,它们很糟糕。我不认为游标在你的场景中不一定是坏主意。

当需要针对多个数据库运行操作(备份,完整性检查,索引维护等)时,使用游标没有问题。当然,您可以构建一个包含数据库名称的临时表并循环执行...但它仍然是一种程序方法。

对于您的具体情况,如果您未根据某些WHERE条款标准删除这些表格中的行,请考虑使用TRUNCATE TABLE代替DELETE FROM。两个操作之间的差异解释了here。请注意,运行TRUNCATE TABLE的用户需要ALTER对受影响对象的权限。

答案 1 :(得分:2)

这将收集一组delete语句并以单个序列运行它们。这不一定是性能更好的,而只是另一种让猫皮肤化的方法。

DECLARE @sql NVARCHAR(MAX); -- if SQL Server 2000, use NVARCHAR(4000)

SET @sql = N'';

SELECT @sql = @sql + N';DELETE ' + name + '..db_table -- more t-sql'
  FROM master.sys.databases
  WHERE name LIKE N'CorpDB%';

SET @sql = STUFF(@sql, 1, 1, '');

EXEC sp_executesql @sql;

您可以考虑在游标内部以类似的方式构建字符串,而不是为每个命令在内部运行EXEC()。如果您要继续使用游标,请使用以下声明:

DECLARE db_cursor CURSOR 
  LOCAL STATIC FORWARD_ONLY READ_ONLY
  FOR

这将具有最少的锁定并且没有不必要的tempdb使用。