sql >> Database teknologi >  >> RDS >> Sqlserver

Sådan gemmer du historiske poster i en historietabel i SQL Server

Grundlæggende ønsker du at spore/revidere ændringer til en tabel, mens du holder den primære tabel lille i størrelse.

Der er flere måder at løse dette problem på. Ulemper og fordele ved hver måde diskuteres nedenfor.

1 - Revision af tabellen med triggere.

Hvis du ønsker at revidere tabellen (indsættelser, opdateringer, sletninger), se på min, hvordan du forhindrer uønskede transaktioner - SQL Saturday slide deck m/code - http://craftydba.com/?page_id=880. Triggeren, der udfylder revisionstabellen, kan indeholde oplysninger fra flere tabeller, hvis du vælger, da dataene er gemt som XML. Derfor kan du om nødvendigt fjerne sletningen af ​​en handling ved at parse XML. Den sporer, hvem og hvad der har foretaget ændringen.

Du kan eventuelt have revisionstabellen på sin egen filgruppe.

Description:
    Table Triggers For (Insert, Update, Delete)
    Active table has current records.
    Audit (history) table for non-active records.

Pros:
    Active table has smaller # of records.
    Index in active table is small.
    Change is quickly reported in audit table.
    Tells you what change was made (ins, del, upd)

Cons:
    Have to join two tables to do historical reporting.
    Does not track schema changes.

2 - Effektiv datering af optegnelserne

Hvis du aldrig kommer til at slette dataene fra revisionstabellen, hvorfor så ikke markere rækken som slettet, men beholde den for altid? Mange systemer som folk bløde bruger effektiv dating til at vise, om en post ikke længere er aktiv. I BI-verdenen kaldes dette en type 2-dimensionel tabel (langsomt skiftende dimensioner). Se artiklen om datavarehusinstituttet. http://www.bidw.org/datawarehousing/scd-type-2/ Hver post har en start- og slutdato.

Alle aktive poster har en slutdato på null.

Description:
    Table Triggers For (Insert, Update, Delete)
    Main table has both active and historical records.

Pros:
    Historical reporting is easy.
    Change is quickly shown in main table.

Cons:
    Main table has a large # of records.
    Index of main table is large.
    Both active & history records in same filegroup.
    Does not tell you what change was made (ins, del, upd)
    Does not track schema changes.

3 - Skift datafangst (Enterprise Feature).

Micorsoft SQL Server 2008 introducerede funktionen til ændring af datafangst. Selvom dette sporer dataændringer (CDC) ved hjælp af en LOG-læser efter kendsgerningen, mangler det ting som hvem og hvad der gjorde ændringen. MSDN-detaljer - http://technet.microsoft.com/en-us/library/bb522489(v=sql.105).aspx

Denne løsning er afhængig af de CDC-job, der kører. Eventuelle problemer med sql-agent vil forårsage forsinkelser i data, der vises.

Se tabeller til ændring af datafangst.http://technet.microsoft.com/en-us/library/bb500353(v=sql.105).aspx

Description:
    Enable change data capture

Pros:
    Do not need to add triggers or tables to capture data.
    Tells you what change was made (ins, del, upd) the _$operation field in 
    <user_defined_table_CT>
    Tracks schema changes.    

Cons:
    Only available in enterprise version.
    Since it reads the log after the fact, time delay in data showing up.
    The CDC tables do not track who or what made the change.
    Disabling CDC removes the tables (not nice)!
    Need to decode and use the _$update_mask to figure out what columns changed.

4 - Skift sporingsfunktion (alle versioner).

Micorsoft SQL Server 2008 introducerede ændringssporingsfunktionen. I modsætning til CDC kommer den med alle versioner; Det kommer dog med en masse TSQL-funktioner, som du skal ringe til for at finde ud af, hvad der skete.

Det blev designet med det formål at synkronisere én datakilde med SQL-server via en applikation. Der er en hel synkroniseringsramme på TechNet.

http://msdn.microsoft.com/en-us/library/bb933874.aspxhttp://msdn.microsoft.com/en-us/library/bb933994.aspxhttp://technet.microsoft.com/en-us/ library/bb934145(v=sql.105).aspx

I modsætning til CDC angiver du, hvor længe ændringer varer i databasen, før de slettes. Indsættelser og sletninger optager heller ikke data. Opdateringer registrerer kun, hvilket felt der er ændret.

Da du synkroniserer SQL-serverkilden til et andet mål, fungerer dette fint. Det er ikke godt til revision, medmindre du skriver et periodisk job for at finde ud af ændringer.

Du bliver stadig nødt til at gemme disse oplysninger et sted.

Description:
    Enable change tracking

Cons:
    Not a good auditing solution

De første tre løsninger vil fungere til din revision. Jeg kan godt lide den første løsning, da jeg bruger den meget i mit miljø.

Med venlig hilsen

John

Kodestykke fra præsentation (Autos Database)

-- 
-- 7 - Auditing data changes (table for DML trigger)
-- 


-- Delete existing table
IF OBJECT_ID('[AUDIT].[LOG_TABLE_CHANGES]') IS NOT NULL 
  DROP TABLE [AUDIT].[LOG_TABLE_CHANGES]
GO


-- Add the table
CREATE TABLE [AUDIT].[LOG_TABLE_CHANGES]
(
  [CHG_ID] [numeric](18, 0) IDENTITY(1,1) NOT NULL,
  [CHG_DATE] [datetime] NOT NULL,
  [CHG_TYPE] [varchar](20) NOT NULL,
  [CHG_BY] [nvarchar](256) NOT NULL,
  [APP_NAME] [nvarchar](128) NOT NULL,
  [HOST_NAME] [nvarchar](128) NOT NULL,
  [SCHEMA_NAME] [sysname] NOT NULL,
  [OBJECT_NAME] [sysname] NOT NULL,
  [XML_RECSET] [xml] NULL,
 CONSTRAINT [PK_LTC_CHG_ID] PRIMARY KEY CLUSTERED ([CHG_ID] ASC)
) ON [PRIMARY]
GO

-- Add defaults for key information
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_CHG_DATE] DEFAULT (getdate()) FOR [CHG_DATE];
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_CHG_TYPE] DEFAULT ('') FOR [CHG_TYPE];
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_CHG_BY] DEFAULT (coalesce(suser_sname(),'?')) FOR [CHG_BY];
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_APP_NAME] DEFAULT (coalesce(app_name(),'?')) FOR [APP_NAME];
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_HOST_NAME] DEFAULT (coalesce(host_name(),'?')) FOR [HOST_NAME];
GO



--
--  8 - Make DML trigger to capture changes
--


-- Delete existing trigger
IF OBJECT_ID('[ACTIVE].[TRG_FLUID_DATA]') IS NOT NULL 
  DROP TRIGGER [ACTIVE].[TRG_FLUID_DATA]
GO

-- Add trigger to log all changes
CREATE TRIGGER [ACTIVE].[TRG_FLUID_DATA] ON [ACTIVE].[CARS_BY_COUNTRY]
  FOR INSERT, UPDATE, DELETE AS
BEGIN

  -- Detect inserts
  IF EXISTS (select * from inserted) AND NOT EXISTS (select * from deleted)
  BEGIN
    INSERT [AUDIT].[LOG_TABLE_CHANGES] ([CHG_TYPE], [SCHEMA_NAME], [OBJECT_NAME], [XML_RECSET])
    SELECT 'INSERT', '[ACTIVE]', '[CARS_BY_COUNTRY]', (SELECT * FROM inserted as Record for xml auto, elements , root('RecordSet'), type)
    RETURN;
  END

  -- Detect deletes
  IF EXISTS (select * from deleted) AND NOT EXISTS (select * from inserted)
  BEGIN
    INSERT [AUDIT].[LOG_TABLE_CHANGES] ([CHG_TYPE], [SCHEMA_NAME], [OBJECT_NAME], [XML_RECSET])
    SELECT 'DELETE', '[ACTIVE]', '[CARS_BY_COUNTRY]', (SELECT * FROM deleted as Record for xml auto, elements , root('RecordSet'), type)
    RETURN;
  END

  -- Update inserts
  IF EXISTS (select * from inserted) AND EXISTS (select * from deleted)
  BEGIN
    INSERT [AUDIT].[LOG_TABLE_CHANGES] ([CHG_TYPE], [SCHEMA_NAME], [OBJECT_NAME], [XML_RECSET])
    SELECT 'UPDATE', '[ACTIVE]', '[CARS_BY_COUNTRY]', (SELECT * FROM deleted as Record for xml auto, elements , root('RecordSet'), type)
    RETURN;
  END

END;
GO



--
--  9 - Test DML trigger by updating, deleting and inserting data
--

-- Execute an update
UPDATE [ACTIVE].[CARS_BY_COUNTRY]
SET COUNTRY_NAME = 'Czech Republic'
WHERE COUNTRY_ID = 8
GO

-- Remove all data
DELETE FROM [ACTIVE].[CARS_BY_COUNTRY];
GO

-- Execute the load
EXECUTE [ACTIVE].[USP_LOAD_CARS_BY_COUNTRY];
GO 

-- Show the audit trail
SELECT * FROM [AUDIT].[LOG_TABLE_CHANGES]
GO

-- Disable the trigger
ALTER TABLE [ACTIVE].[CARS_BY_COUNTRY] DISABLE TRIGGER [TRG_FLUID_DATA];

** Look &Feel af revisionstabellen **



  1. DATE_ADD() Eksempler – MySQL

  2. Hvordan kan jeg finde dublerede fortløbende værdier i denne tabel?

  3. Kan en INNER JOIN tilbyde bedre ydeevne end EKSISTERER

  4. Sådan rangeres over partition i MySQL