2009-03-03 59 views
8

有沒有一種很好的方法可以告訴誰在SQL Server 2005中創建了一個存儲過程(2008年也可以)?在SQL Management Studio中,我可以在一個proc上使用鼠標/屬性來獲取創建的日期/時間,但是如何找到創建者?Microsoft SQL Server - 誰創建了存儲過程?

+0

好的,米奇。 +1 – BuddyJoe 2014-01-07 15:01:57

回答

6

現在對您來說可能已經太遲了,但您可以跟蹤DDL活動。

我們在我們的管理數據庫中有一個表格,它可以獲取所有的活動。它使用了一個DDL觸發器,這是2005年新增的。這些腳本在管理數據庫中創建一個表(SQL_DBA),在模型數據庫上創建觸發器,在現有數據庫上創建觸發器。我還在最後創建了一個sp_msforeachDB語句來禁用所有這些語句。

一個注意事項 - 您的數據庫需要處於兼容模式(每個數據庫的選項爲90),否則您可能會出現錯誤。聲明的EXECUTE AS部分中的帳戶也需要訪問權限才能插入到管理表中。

USE [SQL_DBA] 
GO 
/****** Object: Table [dbo].[DDL_Login_Log] Script Date: 03/03/2009 17:28:10 ******/ 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
CREATE TABLE [dbo].[DDL_Login_Log](
    [DDL_Id] [int] IDENTITY(1,1) NOT NULL, 
    [PostTime] [datetime] NOT NULL, 
    [DB_User] [nvarchar](100) NULL, 
    [DBName] [nvarchar](100) NULL, 
    [Event] [nvarchar](100) NULL, 
    [TSQL] [nvarchar](2000) NULL, 
    [Object] [nvarchar](1000) NULL, 
CONSTRAINT [PK_DDL_Login_Log] PRIMARY KEY CLUSTERED 
(
    [DDL_Id] ASC, 
    [PostTime] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
-------------------------------------------------------------------------------- 
-------------------------------------------------------------------------------- 
--This creates the trigger on the model database so all new DBs get it 
USE [model] 
GO 
/****** Object: DdlTrigger [ddl_DB_User] Script Date: 03/03/2009 17:26:13 ******/ 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
CREATE TRIGGER [ddl_DB_User] 
ON DATABASE 
FOR DDL_DATABASE_SECURITY_EVENTS 
AS 

DECLARE @data XML 
declare @user nvarchar(100) 

SET @data = EVENTDATA() 
select @user = convert(nvarchar(100), SYSTEM_USER) 

execute as login='domain\sqlagent' 
INSERT sql_dba.dbo.DDL_Login_Log 
    (PostTime, DB_User, DBName, Event, TSQL,Object) 
    VALUES 
    (@data.value('(/EVENT_INSTANCE/PostTime)[1]', 'nvarchar(100)'), 
    @user, 
    db_name(), 
    @data.value('(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(100)'), 
    @data.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)'), 
    @data.value('(/EVENT_INSTANCE/ObjectName)[1]', 'nvarchar(1000)') 
) 

GO 
SET ANSI_NULLS OFF 
GO 
SET QUOTED_IDENTIFIER OFF 
GO 


-------------------------------------------------------------------------------- 
-------------------------------------------------------------------------------- 
--CREATE TRIGGER IN ALL NON SYSTEM DATABASES 

DECLARE @dataname varchar(255), 
@dataname_header varchar(255), 
@command VARCHAR(MAX), 
@usecommand VARCHAR(100) 
SET @command = ''; 
DECLARE datanames_cursor CURSOR FOR SELECT name FROM sys.databases 
WHERE name not in ('master', 'pubs', 'tempdb', 'model','msdb') 
OPEN datanames_cursor 
FETCH NEXT FROM datanames_cursor INTO @dataname 
WHILE (@@fetch_status = 0) 
BEGIN 

PRINT '----------BEGIN---------' 

PRINT 'DATANAME variable: ' + @dataname; 

EXEC ('USE ' + @dataname); 

PRINT 'CURRENT db: ' + db_name(); 

SELECT @command = 'CREATE TRIGGER DBA_Audit ON DATABASE 
FOR DDL_DATABASE_LEVEL_EVENTS 
AS 
DECLARE @data XML 
DECLARE @cmd NVARCHAR(1000) 
DECLARE @posttime NVARCHAR(24) 
DECLARE @spid NVARCHAR(6) 
DECLARE @loginname NVARCHAR(100) 
DECLARE @hostname NVARCHAR(100) 
SET @data = EVENTDATA() 
SET @cmd = @data.value(''(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]'', ''NVARCHAR(1000)'') 
SET @cmd = LTRIM(RTRIM(REPLACE(@cmd,'''',''''))) 
SET @posttime = @data.value(''(/EVENT_INSTANCE/PostTime)[1]'', ''DATETIME'') 
SET @spid = @data.value(''(/EVENT_INSTANCE/SPID)[1]'', ''nvarchar(6)'') 
SET @loginname = @data.value(''(/EVENT_INSTANCE/LoginName)[1]'', 
    ''NVARCHAR(100)'') 
SET @hostname = HOST_NAME() 
INSERT INTO [DBA_AUDIT].dbo.AuditLog(Command, PostTime,HostName,LoginName) 
VALUES(@cmd, @posttime, @hostname, @loginname);' 

EXEC (@command); 
FETCH NEXT FROM datanames_cursor INTO @dataname; 
PRINT '----------END---------' 
END 
CLOSE datanames_cursor 
DEALLOCATE datanames_cursor 

-------------------------------------------------------------------------------- 
-------------------------------------------------------------------------------- 

----Disable all triggers when things go haywire 
sp_msforeachdb @command1='use [?]; IF EXISTS (SELECT * FROM sys.triggers WHERE name = N''ddl_DB_User'' AND parent_class=0)disable TRIGGER [ddl_DB_User] ON DATABASE' 
3

我相信這在SQL 2005中不可用。當然,它在SQL Management Studio中的屬性中不可用,並且在sys.objects表或其他任何我可以看到的表中都不可用。

3

如果未創建不久之前,試試這個:

DECLARE @path varchar(256) 

SELECT @path = path 
FROM sys.traces 
where id = 1 

SELECT * 
FROM fn_trace_gettable(@path, 1) 

它選擇當前(開箱)默認跟蹤。如果它是最近創建的(並且服務器最近尚未重新啓動),則存儲過程對象名稱和創建它的登錄名將位於跟蹤數據中。

+0

@布魯諾廷德爾:你怎麼走? – 2009-03-04 00:35:40

+0

This proc創建於3年前。猜猜這是行不通的。另外,當我試圖運行它時,我得到了「你沒有權限運行'SYS.TRACES'。」猜猜我可以讓DBA來運行它。但... – BuddyJoe 2009-03-04 17:33:34

+0

我認爲你所說的痕跡信息僅適用於一天,一週或者一個月? – BuddyJoe 2009-03-04 17:34:40

2

沿着相同的思路山姆,你可以使用一個DDL觸發器來捕捉所需要的信息,然後發送數據到SQL服務代理隊列,這可能將其轉發給管理數據庫(這可能是上另一個服務器,如果需要的話),然後將保存所有的DDL變化。

這將刪除權限問題,因爲DDL觸發器將數據加載到本地數據庫的Service Broker隊列中,並且SQL處理將消息移動到其他數據庫。

用這種方法會有更多的設置,但是一旦設置它就可以工作,不管是誰改變了對象。

0

如何獲得這條信息事後(特別是幾年後)很可能是不可能的。

但是,您可以使用SQL Server Profiler來跟蹤DDL操作。在事件選擇,檢查以下項目:

對象/對象:改變了

對象/對象:創建

對象/對象:刪除

也有大量的定製選項:可以將輸出保存到文件或表格中,並根據任何列等過濾輸出等。