Microsoft SQL Server - 谁创建了存储过程?

9

有没有好的方法可以告诉我如何查看SQL Server 2005(也适用于2008)中存储过程的创建者?在SQL Management Studio中,我可以右键/属性单击proc以获取创建日期/时间,但我该如何发现创建者?

5个回答

7

现在可能已经太晚了,但是你可以追踪数据库定义语言(DDL)活动。

我们在管理数据库中有一个表格用于记录所有的活动。它使用了2005年新增的DDL触发器。这些脚本会在你的管理员数据库(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'

但是如果您的权限/角色设置正确,您需要多久才需要这个? - Mitch Wheat
如果您的系统已经非常安全,您可能不需要这个。 我每天都会收到这个列表,出于我自己的目的,我不会深入讨论。 - Sam
+1 酷的概念。完全忘记了DDL触发器。这可能有助于未来的“监视”。但是Mitch提出了一个关于安全性的好问题。 - BuddyJoe
我可以问一下最后一行吗?是什么导致它变得“失控”。您能在回答的末尾详细说明一些吗? - BuddyJoe
如果您将此应用于所有生产数据库,并且某些内容停止工作,那么能够快速撤销是很好的。我喜欢将这样的东西打包起来,以便可以轻松地应用或删除它。我并不是完全认真地说事情会变得一团糟。 - Sam
是的,我们都努力追求完美的安全性,但有时应用程序和组织上的“障碍”会阻碍我们的路线。这个日志可以告诉您哪些拥有提升生产权限的开发人员没有遵循变更流程,或者供应商提供的应用程序正在做什么,或者经过授权的用户进行了更改。 - Sam

5
如果创建时间不是太久之前,可以尝试以下方法:
DECLARE @path varchar(256)

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

SELECT *
FROM fn_trace_gettable(@path, 1)

它选择当前(开箱即用的)默认跟踪。如果它是最近创建的(且服务器最近未重新启动),则存储过程对象名称和创建它的登录名将在跟踪数据中。


@布鲁诺·泰德尔:你最后怎么样了? - Mitch Wheat
这个存储过程是3年前创建的。我猜这不会起作用。而且,当我尝试运行它时,我得到了“您没有运行'SYS.TRACES'的权限。”我想我可以要求DBA来运行它。但是... - BuddyJoe
我认为你所说的痕迹信息只能保留一天、一周或者一个月左右,是这个意思吧? - BuddyJoe
正确的,SQL Server不会保留其默认跟踪数据太长时间,因为它会很快填满硬盘。 - mrdenny
黑盒跟踪非常有用:http://mitch-wheat.blogspot.com/2009/01/sql-servers-built-in-traces.html - Mitch Wheat

3

我相信这在SQL 2005中是不可用的。当然,在SQL Management Studio的属性中也无法找到它,在sys.objects表或其他我所看到的表中也没有。


2
与Sam的想法相同,您可以使用DDL触发器来捕获所需信息,然后将该数据发送到SQL Service broker队列,该队列可以将其转发到Admin数据库(如果需要,可以在另一台服务器上),该数据库将保存所有DDL更改。这将消除权限问题,因为DDL触发器将在本地数据库中将数据加载到Service Broker队列中,而SQL会处理将消息移动到其他数据库的操作。虽然此方法需要进行一些设置,但一旦设置完成,它将适用于任何人对对象进行更改。

这样会更加流畅。现在,如果我们复制一个数据库并将其交给开发人员,他们会在ddl修改上遇到错误。 - Sam

0

如何在事后(尤其是几年后)获取此信息可能是不可能的。

但是,您可以使用SQL Server Profiler跟踪DDL操作。在事件选择中,勾选以下事件:

对象/对象:已更改

对象/对象:已创建

对象/对象:已删除

还有很多自定义选项:您可以将输出保存到文件或表中,根据任何列进一步过滤输出等等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接