2009-03-03 16 views

risposta

6

Potrebbe essere troppo tardi per te ora, ma puoi tenere traccia dell'attività DDL.

Abbiamo una tabella nel nostro database amministrativo che ottiene tutta l'attività inserita. Usa un trigger DDL, nuovo al 2005. Questi script creano una tabella nel tuo DB di amministrazione (SQL_DBA per me), creano un trigger sul modello db, creano trigger su database esistenti. Ho anche creato un'istruzione sp_msforeachDB alla fine per disabilitarli tutti.

Un avvertimento - i database devono essere in modalità di compatibilità di 90 (in opzioni per ciascun db), altrimenti è possibile che si verifichino errori. Anche l'account nella parte EXECUTE AS dell'istruzione deve essere inserito nella tabella di amministrazione.

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

Ma se hai i permessi/ruoli impostati correttamente, come spesso ti serve questo? –

+0

Se il sistema è chiuso, potrebbe non essere necessario. Ho questa lista spedita per me ogni giorno per i miei scopi a cui non entrerò. – Sam

+0

+1 Cool concept. Hai dimenticato tutti i trigger DDL. Ciò potrebbe aiutare per il futuro "guardare". Ma Mitch porta un buon punto sulla sicurezza. – BuddyJoe

3

Credo che questo non sia disponibile in SQL 2005. Certamente non è disponibile nelle proprietà in SQL Management Studio e non è disponibile nella tabella sys.objects o in altri che posso vedere.

3

Se non è stato creato molto tempo fa, provate questo:

DECLARE @path varchar(256) 

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

SELECT * 
FROM fn_trace_gettable(@path, 1) 

seleziona la corrente (out of the box) traccia predefinita. Se è stato creato di recente (e il server non è stato riavviato di recente), il nome dell'oggetto della procedura memorizzata e il nome di accesso che lo ha creato saranno nei dati di traccia.

+0

@Bruno Tyndall: come sei andato? –

+0

Questo proc è stato creato 3 anni fa. Credo che questo non funzionerebbe. Inoltre, quando ho provato a eseguirlo ho ottenuto "Non hai il permesso di eseguire" SYS.TRACES "." Credo di poter chiedere al DBA di eseguirlo. Ma... – BuddyJoe

+0

Penso che quello che stai dicendo è che le informazioni sulle tracce vanno bene solo per circa un giorno, una settimana, forse un mese? – BuddyJoe

2

Lungo la stessa idea di Sam, è possibile utilizzare un trigger DDL per acquisire le informazioni necessarie, quindi inviare i dati a una coda broker di SQL servizio, che potrebbe trasmettere al database di amministrazione (che potrebbe essere il un altro server se necessario) che quindi conserverebbe tutte le modifiche DDL.

Questo eliminerebbe il problema delle autorizzazioni poiché il trigger DDL caricherà i dati in una coda di Service Broker nel database locale e SQL gestirà lo spostamento del messaggio nell'altro database.

Ci sarebbe un po 'più di setup con questo metodo, ma una volta configurato funzionerebbe, indipendentemente da chi ha modificato l'oggetto.

+0

+1 questo sembra piuttosto promettente – BuddyJoe

+0

Questo è molto più lucido. Ora, se facciamo una copia di un database e lo diamo allo sviluppatore, otterranno errori su mod ddl. – Sam

0

Come ottenere questa informazione ex post (soprattutto anni dopo) è più probabile che non sia possibile.

Tuttavia, è possibile utilizzare SQL Server Profiler per tenere traccia delle azioni DDL. In Selezione eventi, controllare i seguenti eventi:

Oggetti/Oggetto: Altered

oggetti/Oggetto: Creato

oggetti/Oggetto: soppresso

ci sono anche un sacco di opzioni di personalizzazione: è possibile salva l'output in un file o in una tabella, filtra l'output inoltre in base alle colonne ecc. ecc.

Problemi correlati