获取使用游标但未明确关闭/取消分配它们的活动对象的列表

Sea*_*ong 4 sql-server sql-server-2014

有时我们的开发人员会编写一个使用游标的查询,但不会明确地关闭它们。我正在尝试在我的生产数据库中生成一个活动对象列表,这些对象使用游标但没有明确关闭/取消分配它们。为此,我编写了一个简单的语句来完成这项工作,但速度非常慢:

select distinct name, 
            definition
from   SYS.SQL_MODULES 
   inner join SYS.OBJECTS O 
           on SQL_MODULES.OBJECT_ID = O.OBJECT_ID 
where  SQL_MODULES.DEFINITION like '%open%'
   and SQL_MODULES.DEFINITION like '%declare % cursor%'
   and ( SQL_MODULES.DEFINITION not like '%close%' 
          or SQL_MODULES.DEFINITION not like '%deallocate%' )
Run Code Online (Sandbox Code Playgroud)

目前,这需要大约 3 分钟才能运行。有没有更好的方法来获取我正在寻找的信息?

Eri*_*ing 6

与其在所有存储过程文本中搜索这些通配符,不如查找打开的游标及其关联文本。这可能会更容易找到由健忘的开发人员编写的游标名称、存储过程等。

要进行测试,请在一个窗口中运行它:

SET NOCOUNT ON; 

IF OBJECT_ID('tempdb..#commands') IS NOT NULL
   BEGIN
         DROP TABLE #commands;
   END;

CREATE TABLE #commands
(
  ID INT IDENTITY(1, 1)
         PRIMARY KEY CLUSTERED,
  Command NVARCHAR(2000)
);
DECLARE @CurrentCommand NVARCHAR(2000);

INSERT INTO #commands ( Command )
    SELECT 'SELECT 1';

DECLARE result_cursor CURSOR
FOR
        SELECT Command
            FROM #commands;

OPEN result_cursor;
FETCH NEXT FROM result_cursor INTO @CurrentCommand;
WHILE @@FETCH_STATUS = 0
      BEGIN 

            EXEC (@CurrentCommand);

            FETCH NEXT FROM result_cursor INTO @CurrentCommand;
      END;

--CLOSE result_cursor;
--DEALLOCATE result_cursor;
Run Code Online (Sandbox Code Playgroud)

然后在另一个窗口中,运行:

SELECT dec.session_id, dec.cursor_id, dec.name, dec.properties, dec.creation_time, dec.is_open, dec.is_close_on_commit,
        dec.fetch_status, dec.worker_time, dec.reads, dec.writes, dec.dormant_duration, dest.text
    FROM sys.dm_exec_cursors (0) AS dec
    CROSS APPLY sys.dm_exec_sql_text(dec.sql_handle) AS dest
    WHERE dec.is_open = 1;
Run Code Online (Sandbox Code Playgroud)

坚果

您应该在此处看到其他会话打开的光标以及任何其他打开的光标。

如果您需要监控这些(并且您没有监控工具),您可以使用 dormant_duration 列并使用代理作业轮询该 DMV,当打开的游标处于休眠状态时,代理作业将触发警报或电子邮件多少时间。那是以毫秒为单位。

希望这可以帮助!