有没有一种好方法可以告诉谁在SQL Server 2005中创建了一个存储过程(也适用于2008年)?在SQL Management Studio中,我可以在proc上使用鼠标/属性来获取创建的日期/时间,但是如何发现创建者呢?
答案 0 :(得分: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'
答案 1 :(得分:3)
我相信这在SQL 2005中不可用。当然它在SQL Management Studio的属性中不可用,并且在sys.objects表或我能看到的任何其他表中都不可用。
答案 2 :(得分:3)
如果它不是很久以前创建的,请试试这个:
DECLARE @path varchar(256)
SELECT @path = path
FROM sys.traces
where id = 1
SELECT *
FROM fn_trace_gettable(@path, 1)
选择当前(开箱即用)默认曲线。如果它是最近创建的(并且服务器最近没有重新启动),那么存储过程对象名称和创建它的登录名将位于跟踪数据中。
答案 3 :(得分:2)
与Sam的想法一样,您可以使用DDL触发器捕获所需信息,然后将该数据发送到SQL Service代理队列,该队列可以将其转发到Admin数据库(如果需要,可以在另一台服务器上) )然后将保留所有DDL更改。
这将删除权限问题,因为DDL触发器将数据加载到本地数据库的Service Broker Queue中,并且SQL处理将消息移动到其他数据库。
使用此方法会有更多设置,但一旦设置,无论是谁更改了对象都会有效。
答案 4 :(得分:0)
如何在事后(尤其是数年之后)获得这条信息很可能是不可能的。
但是,您可以使用SQL Server Profiler来跟踪DDL操作。在事件选择中,检查以下事件:
对象/对象:改变
Objects / Object:Created
对象/对象:已删除
还有很多自定义选项:您可以将输出保存到文件或表格,根据任何列等进一步过滤输出等。