AnO*_*oul 6 sql-server-2008 stored-procedures profiler extended-events trace
我有一个问题,某个存储过程偶尔会消失,我需要找出哪个脚本删除了它。我发现这段代码给出了与删除这个存储过程相关的事件。
DECLARE @path NVARCHAR(260);
SELECT
@path = REVERSE(SUBSTRING(REVERSE([path]),
CHARINDEX(CHAR(92), REVERSE([path])), 260)) + N'log.trc'
FROM sys.traces
WHERE is_default = 1;
SELECT
LoginName,
HostName,
StartTime,
ObjectName,
TextData
FROM sys.fn_trace_gettable(@path, DEFAULT)
WHERE EventClass = 47 -- Object:Deleted
AND EventSubClass = 1
AND ObjectName like N'%usp_GetPendingConfiguration%'
ORDER BY StartTime DESC;
Run Code Online (Sandbox Code Playgroud)
有没有办法可以找到哪个存储过程或事件删除了这个存储过程?请指教。
对于删除此存储过程的任何查询,从 DDL 触发器获取 SQL 只会有很大帮助。如果查询来自存储过程中的动态 SQL,或来自发布脚本,或集成测试、应用程序代码等,那么您可能只会捕获DROP PROCEDURE ...
那些并没有提供太多线索的被处决。
然而,这并不意味着 DDL 触发器不是解决这个问题的方法。与其仅仅捕获 SQL 并尝试推断源,因为此操作是不需要的(并且可能会破坏调用正在删除的存储过程的任何代码),因此应该简单地禁止它。您可以DROP PROCEDURE
使用 DDL 触发器捕获事件,然后通过从EVENTDATA()
函数返回的 XML 检查正在删除哪个过程。如果正在删除的存储过程是有问题的存储过程,则执行以下内容:
RAISERROR('Ah ha! Caught you red-handed (whatever that means). No DROP for you!', 16, 1);
ROLLBACK;
Run Code Online (Sandbox Code Playgroud)
这样做:
以下是一个更完整的示例,包括记录事件的功能,以防万一,因为它至少可以让您了解哪些人或进程正在执行此操作,以及执行此操作的频率:
CREATE TRIGGER [PreventDropGetPendingConfiguration]
ON DATABASE
FOR DROP_PROCEDURE
AS
SET NOCOUNT ON;
IF (EVENTDATA().value(N'(EVENT_INSTANCE/ObjectName/text())[1]', 'sysname')
= N'usp_GetPendingConfiguration')
BEGIN
-- store values in variables as ROLLBACK will erase EVENTDATA()
DECLARE @EventTime DATETIME,
@LoginName sysname, -- lower-case for case-sensitive servers
@UserName sysname, -- lower-case for case-sensitive servers
@CommandText NVARCHAR(MAX),
@SPID INT;
DECLARE @InputBuffer TABLE
(
EventType NVARCHAR(30),
[Parameters] SMALLINT,
EventInfo NVARCHAR(4000)
);
SELECT @EventTime =
EVENTDATA().value(N'(EVENT_INSTANCE/PostTime/text())[1]', 'DATETIME'),
@LoginName =
EVENTDATA().value(N'(EVENT_INSTANCE/LoginName/text())[1]', 'sysname'),
@UserName =
EVENTDATA().value(N'(EVENT_INSTANCE/UserName/text())[1]', 'sysname'),
@CommandText =
EVENTDATA().value(N'(EVENT_INSTANCE/TSQLCommand/CommandText/text())[1]',
'NVARCHAR(MAX)'),
@SPID = EVENTDATA().value(N'(EVENT_INSTANCE/SPID/text())[1]', 'INT');
-- RollBack now else logging will also get Rolled Back ;-)
ROLLBACK;
IF (OBJECT_ID(N'dbo.LoggyLog') IS NULL)
BEGIN
CREATE TABLE dbo.LoggyLog
(
LoggyLogID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
EventTime DATETIME NOT NULL,
LoginName sysname, -- lower-case for case-sensitive servers
UserName sysname, -- lower-case for case-sensitive servers
CommandText NVARCHAR(MAX) NOT NULL,
SPID INT NOT NULL,
EventInfo NVARCHAR(4000) NULL
);
END;
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'DBCC INPUTBUFFER ( ' + CONVERT(NVARCHAR(10), @SPID)
+ N' ) WITH NO_INFOMSGS;';
INSERT INTO @InputBuffer (EventType, [Parameters], EventInfo)
EXEC(@SQL);
INSERT INTO dbo.LoggyLog (EventTime, LoginName, UserName, CommandText,
SPID, EventInfo)
SELECT @EventTime, @LoginName, @UserName, @CommandText, @SPID, tmp.EventInfo
FROM @InputBuffer tmp;
RAISERROR('Ah ha! Caught you red-handed (whatever that means **). No DROP for you!',
16, 1);
END;
GO
Run Code Online (Sandbox Code Playgroud)
任何删除此存储过程的尝试都将收到以下错误:
Msg 50000, Level 16, State 1, Procedure PreventDropProcedure, Line 7
啊哈!当场抓住你(不管那意味着什么)。没有 DROP 给你!消息 3609,级别 16,状态 2,第 1 行
事务在触发器中结束。该批次已中止。
我使用DBCC INPUTBUFFER
而不是的原因sys.dm_exec_sql_text
是sys.dm_exec_sql_text
返回正在执行的当前查询。如果sys.dm_exec_sql_text
在触发器本身内进行本地查询,您将得到该CREATE TRIGGER...
语句。如果在动态 SQL 或子存储过程调用中查询该 DMV,那么您将获得这些特定查询,甚至不会获得调用它们的查询CREATE TRIGGER
。所有这些都是没有用的。
相比之下,DBCC INPUTBUFFER
报告链中的第一批(不仅仅是当前查询),并且至少可以用于跟踪导致调用的任意数量的后续调用DROP
。
此外,鉴于这只是有时发生,有人可能忘记了GO
在调用CREATE PROCEDURE
之前正在执行的发布脚本中的 a DROP PROCEDURE
,并且不小心将DROP
查询作为正在创建的存储过程的一部分(这种情况更常发生在GRANT EXECUTE
语句,因为它们通常遵循CREATE PROCEDURE
语句)。这可能是由于发布脚本中的以下内容而发生的:
CREATE PROCEDURE dbo.ProcName
AS
...
-- missing GO !!!!
IF (OBJECT_ID(N'dbo.ProcGettingDropped') IS NOT NULL)
BEGIN
DROP PROCEDURE dbo.ProcGettingDropped;
END;
GO -- this GO terminates the CREATE PROCEDURE statement
Run Code Online (Sandbox Code Playgroud)
您可以通过运行以下查询在包含正在删除的存储过程的数据库中搜索此事件的出现:
SELECT OBJECT_NAME([object_id]) AS [ObjectName], *
FROM sys.sql_modules
WHERE [definition] LIKE N'%DROP%';
Run Code Online (Sandbox Code Playgroud)
**红手的词源(感谢@MartinSmith)
归档时间: |
|
查看次数: |
1798 次 |
最近记录: |