2009-03-03 24 views

Respuesta

6

Puede ser demasiado tarde para usted ahora, pero puede realizar un seguimiento de la actividad de DDL.

Tenemos una tabla en nuestra base de datos administrativa que obtiene toda la actividad puesta en ella. Utiliza un activador DDL, nuevo en 2005. Estos scripts crean una tabla en su DB de administración (SQL_DBA para mí), crean un desencadenador en el modelo db, crean desencadenantes en bases de datos existentes. También creé una instrucción sp_msforeachDB al final para deshabilitarlas todas.

Una advertencia - sus bases de datos deben estar en el modo de compatibilidad de 90 (en opciones para cada db), de lo contrario, puede comenzar a recibir errores. La cuenta en la sección EJECUTAR COMO de la declaración también necesita acceso para insertarla en su tabla administrativa.

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' 
+0

Pero si tiene sus permisos/roles configurados correctamente, ¿cómo? a menudo necesitas esto? –

+0

Si tiene el sistema abrochado, es posible que no lo necesite. Tengo esta lista enviada por correo a diario para mis propios fines. No entraré. – Sam

+0

+1 Cool concept. Olvidé todo sobre los disparadores DDL. Eso podría ayudar a "mirar" en el futuro. Pero Mitch saca un buen punto acerca de la seguridad. – BuddyJoe

3

Creo que esto no está disponible en SQL 2005. Ciertamente no está disponible en las propiedades de SQL Management Studio, y no está disponible en la tabla sys.objects ni en ninguna otra que pueda ver.

3

Si no se creó hace mucho tiempo, intente esto:

DECLARE @path varchar(256) 

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

SELECT * 
FROM fn_trace_gettable(@path, 1) 

Se selecciona la corriente (de la caja) de seguimiento predeterminado. Si se creó recientemente (y el servidor no se ha reiniciado recientemente), el nombre del objeto del procedimiento almacenado y el nombre de inicio de sesión que lo creó estarán en los datos de seguimiento.

+0

@Bruno Tyndall: entonces, ¿cómo fuiste? –

+0

Este proceso fue creado hace 3 años. Supongo que esto no funcionaría. Además, cuando traté de ejecutarlo, recibí "No tienes permiso para ejecutar 'SYS.TRACES'". Creo que podría pedirle al DBA que lo ejecute. Pero... – BuddyJoe

+0

Creo que lo que dices es que la información de los rastros solo sirve para un día, una semana o quizás un mes. – BuddyJoe

2

A lo largo de la misma idea que Sam, se puede utilizar un desencadenador DDL para capturar la información necesaria, a continuación, enviar esos datos a una cola de agente de servicios de SQL, lo que podría remitirlo a la base de datos de administración (que podría ser el otro servidor si es necesario) que luego mantendría todos los cambios de DDL.

Esto eliminaría el problema de los permisos ya que el desencadenador DDL estaría cargando datos en una cola de Service Broker en la base de datos local y SQL se encarga del traslado del mensaje a la otra base de datos.

Habría un poco más de configuración con este método, pero una vez configurada funcionaría sin importar quién hizo el cambio de objeto.

+0

+1 esto suena bastante prometedor – BuddyJoe

+0

Eso es mucho más pulido. Ahora, si hacemos una copia de una base de datos y se la damos al desarrollador, obtendrán errores en mods ddl. – Sam

0

Cómo es posible que no se pueda obtener esta información ex post (especialmente años después).

Sin embargo, puede usar el Analizador de SQL Server para rastrear las acciones de DDL. En Selección de Eventos, compruebe los siguientes eventos:

Objetos/Object: Altered

Objetos/Object: Creado

Objetos/Object: suprimido

También hay un montón de opciones de personalización: se puede guarde la salida en un archivo o tabla, filtre la salida además basado en cualquier columna etc. etc.

Cuestiones relacionadas