2012-08-09 25 views
17

में इतिहास तालिका में ऐतिहासिक रिकॉर्ड कैसे संग्रहीत करें मेरे पास 2 टेबल, Table-A और Table-A-History हैं।SQL सर्वर

  • Table-A वर्तमान डेटा पंक्तियां शामिल हैं।
  • Table-A-History ऐतिहासिक डेटा

मैं Table-A में अपने डेटा के सबसे वर्तमान पंक्ति करना चाहते हैं, और Table-A-History ऐतिहासिक पंक्तियों से युक्त होता है। insert into select या के माध्यम से

  1. जब भी कोई नया डेटा पंक्ति उपलब्ध है, Table-A-History को Table-A से वर्तमान पंक्ति के लिए कदम और नवीनतम आंकड़ों के साथ Table-A पंक्ति (अद्यतन:

    मैं यह पूरा करने के 2 तरीके के बारे में सोच सकते हैं select into table)

    या

  2. जब भी कोई नया डेटा पंक्ति उपलब्ध है, Table-A की पंक्ति को अद्यतन करने और एक सम्मिलित ew पंक्ति Table-A-History में।

प्रदर्शन के संबंध में विधि 1 या 2 बेहतर है? क्या इसे पूरा करने के लिए एक बेहतर तरीका है?

+2

क्या आपने 'टेबल-ए-हिस्ट्री 'पंक्तियों को बनाने के लिए' टेबल-ए 'पर ट्रिगर्स का उपयोग करने पर विचार किया है? सुनिश्चित करें कि वे अंतिम ([sp_settriggerorder] (http://msdn.microsoft.com/en-us/library/ms186762.aspx) को आग लगाने के लिए सेट हैं)। – HABO

+0

नहीं, मैंने नहीं किया है। मैं ट्रिगर्स में देखूंगा। धन्यवाद। – Mausimo

उत्तर

18

लॉगिंग परिवर्तन कुछ ऐसा है जो मैंने आमतौर पर लॉग तालिका में परिवर्तन रिकॉर्ड करने के लिए आधार तालिका पर ट्रिगर्स का उपयोग करके किया है। लॉग इन तालिका में डेटाबेस उपयोगकर्ता, क्रिया और दिनांक/समय रिकॉर्ड करने के लिए अतिरिक्त कॉलम हैं।

create trigger Table-A_LogDelete on dbo.Table-A 
    for delete 
as 
    declare @Now as DateTime = GetDate() 
    set nocount on 
    insert into Table-A-History 
    select SUser_SName(), 'delete-deleted', @Now, * 
     from deleted 
go 
exec sp_settriggerorder @triggername = 'Table-A_LogDelete', @order = 'last', @stmttype = 'delete' 
go 
create trigger Table-A_LogInsert on dbo.Table-A 
    for insert 
as 
    declare @Now as DateTime = GetDate() 
    set nocount on 
    insert into Table-A-History 
    select SUser_SName(), 'insert-inserted', @Now, * 
     from inserted 
go 
exec sp_settriggerorder @triggername = 'Table-A_LogInsert', @order = 'last', @stmttype = 'insert' 
go 
create trigger Table-A_LogUpdate on dbo.Table-A 
    for update 
as 
    declare @Now as DateTime = GetDate() 
    set nocount on 
    insert into Table-A-History 
    select SUser_SName(), 'update-deleted', @Now, * 
     from deleted 
    insert into Table-A-History 
    select SUser_SName(), 'update-inserted', @Now, * 
     from inserted 
go 
exec sp_settriggerorder @triggername = 'Table-A_LogUpdate', @order = 'last', @stmttype = 'update' 

लॉगिंग ट्रिगर्स को हमेशा अंतिम बार आग लगाना चाहिए। अन्यथा, बाद वाला ट्रिगर मूल लेनदेन को रोलबैक कर सकता है, लेकिन लॉग तालिका पहले ही अपडेट हो चुकी है। यह मामलों की एक भ्रमित स्थिति है।

4

विधि 3 के बारे में कैसे: Table-ATable-A-History के विरुद्ध एक दृश्य बनाएं। Table-A-History में डालें और उचित फ़िल्टरिंग तर्क Table-A उत्पन्न करें। इस तरह आप केवल एक टेबल में डालने जा रहे हैं।

+1

मैंने सोचा कि मुझे टेबल को अलग करना चाहिए, क्योंकि टेबल-ए में ~ 10 के रिकॉर्ड होंगे जो अक्सर उपयोग किए जा रहे हैं। जहां इतिहास तालिका विशाल हो जाएगी और बहुत कम उपयोग किया जाएगा। तालिका-ए की तुलना में 5-10% समय। निष्पादन के अनुसार, यदि तालिका-ए और टेबल-ए-हिस्ट्री – Mausimo

+0

संयुक्त रूप से संभवतः संभवतः नहीं, तो चयन के लिए आवेषण के अनुपात के आधार पर, संभवतः नहीं, एक विशाल तालिका के बजाय डेटाबेस को 10 के रिकॉर्ड के माध्यम से खोजना बेहतर नहीं होगा। आप टेबल-ए को एक अनुक्रमित दृश्य भी बना सकते हैं (http://msdn.microsoft.com/en-us/library/dd171921%28v=sql.100%29.aspx)। यह आपके लिए खोज समस्या को हल कर सकता है। – mwigdahl

3

हालांकि इसे और अधिक स्थान लेता है, इतिहास के साथ हाल ही में रिकॉर्ड युक्त टेबल रिपोर्ट लिखने और देखकर आप दर्द की बचत होगी कैसे परिवर्तन हुए और जब हो रही है। मेरी राय में सोचने के लायक कुछ।

जहां तक ​​प्रदर्शन, मैं उन्हें समान होने की उम्मीद करता हूं। लेकिन, आप निश्चित रूप से गैर-हिस्ट टेबल से रिकॉर्ड (विकल्प 1 का "चाल") को मिटाना नहीं चाहते हैं क्योंकि आप दो तालिकाओं के बीच रेफरेंसियल अखंडता का उपयोग कर रहे हैं, है ना?

+0

ठीक है, मैं तालिका ए में रिकॉर्ड अपडेट करूँगा। तालिका-ए-इतिहास तालिका एक सरोगेट कुंजी का उपयोग करती है + तालिका-ए – Mausimo

2

मैं विधि पसंद करेंगे 1
इसके अलावा, मैं भी होगा इतिहास तालिका में मौजूदा रिकॉर्ड को बनाए रखने के भी
यह जरूरत पर निर्भर करता है।

3

विकल्प 1 ठीक है। लेकिन आप भी विधि 4 :)

  1. सम्मिलित अपनी तालिका में नया रिकार्ड है,

  2. ले जाएँ पुराने रिकॉर्ड mysql अनुसूचक का उपयोग कर नियमित आधार पर तालिका संग्रह करने के लिए। आप न्यूनतम लोड के समय डेटा संग्रह को शेड्यूल कर सकते हैं, उदाहरण के लिए रात के समय में।

+1

से जुड़ी एक विदेशी कुंजी, क्षमा करें। लेकिन विचार वही है। यदि आप दिन के दौरान प्रदर्शन में ढीला नहीं करना चाहते हैं, तो बस रात में ऐसा करें ;-) – Vahan

+0

मुझे लगता है कि प्रश्न न केवल INSERT के बारे में है, बल्कि अद्यतन और DELETEs भी है। क्या होगा यदि एक डाली गई पंक्ति उसी दिन अपडेट या हटा दी जाती है? उस स्थिति में, उसी दिन किए गए परिवर्तनों को ट्रैक करना संभव नहीं है। (यदि प्रश्न केवल आईएनएसईआरटी के बारे में है, तो ऑडिट तालिका की आवश्यकता नहीं है, क्योंकि केवल INSERT का उपयोग करके कोई डेटा नहीं बदला जाएगा।) – beawolf

36

मूल रूप से आप प्राथमिक तालिका को छोटे आकार में रखते हुए तालिका में परिवर्तनों को ट्रैक/ऑडिट करना चाहते हैं।

इस समस्या को हल करने के कई तरीके हैं। प्रत्येक तरीके के विपक्ष और पेशेवरों पर चर्चा की गई है।

1 - ट्रिगर्स के साथ तालिका का ऑडिटिंग।

यदि आप तालिका (आवेषण, अद्यतन, हटाए गए) का ऑडिट करना चाहते हैं, तो अनचाहे लेन-देन को वापस करने के तरीके को देखें - एसक्यूएल शनिवार स्लाइड डेक डब्ल्यू/कोड - http://craftydba.com/?page_id=880। ऑडिट तालिका भरने वाला ट्रिगर एकाधिक टेबल से जानकारी रख सकता है, यदि आप चुनते हैं, क्योंकि डेटा एक्सएमएल के रूप में सहेजा जाता है। इसलिए, यदि आप XML को पार्स करके आवश्यक हो तो कार्रवाई को अन-हटा सकते हैं। यह ट्रैक करता है कि किसने और क्या परिवर्तन किया।

वैकल्पिक रूप से, आपके पास अपने स्वयं के फ़ाइल समूह पर ऑडिट तालिका हो सकती है।

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 - प्रभावी रिकॉर्ड

तुम कभी नहीं लेखा परीक्षा तालिका से डेटा शुद्ध करने के लिए जा रहे हैं डेटिंग, के रूप में नष्ट क्यों पंक्ति चिह्नित नहीं है, लेकिन यह हमेशा के लिए रहते हैं? लोगों की तरह कई प्रणालियों को नरम उपयोग प्रभावी दिखाने के लिए दिखाता है कि रिकॉर्ड अब सक्रिय नहीं है। बीआई दुनिया में इसे एक प्रकार 2 आयामी तालिका (धीरे-धीरे आयाम बदलना) कहा जाता है। डेटा गोदाम संस्थान लेख देखें। http://www.bidw.org/datawarehousing/scd-type-2/ प्रत्येक रिकॉर्ड की शुरुआत और समाप्ति तिथि है।

सभी सक्रिय रिकॉर्डों की शून्य समाप्ति तिथि है।

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 - बदलें डाटा कैप्चर (उद्यम फीचर)।

माइक्रोसॉफ्ट एसक्यूएल सर्वर 2008 ने परिवर्तन डेटा कैप्चर फीचर पेश किया। हालांकि, इस तथ्य के बाद एक LOG रीडर का उपयोग कर डेटा परिवर्तन (सीडीसी) ट्रैक करता है, इसमें ऐसी चीजों की कमी है जैसे परिवर्तन और किसने बदलाव किया। एमएसडीएन विवरण - http://technet.microsoft.com/en-us/library/bb522489(v=sql.105).aspx

यह समाधान सीडीसी नौकरियों पर चल रहा है। एसक्यूएल एजेंट के साथ कोई भी समस्या डेटा दिखाने में देरी का कारण बन जाएगी।

परिवर्तन डेटा कैप्चर टेबल देखें। 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 - बदलें ट्रैकिंग सुविधा (सभी संस्करण)।

माइक्रोसॉफ्ट एसक्यूएल सर्वर 2008 ने परिवर्तन ट्रैकिंग सुविधा पेश की। सीडीसी के विपरीत, यह सभी संस्करणों के साथ आता है; हालांकि, यह टीएसक्यूएल कार्यों के समूह के साथ आता है जिसे आपको यह पता लगाने के लिए बुलाया जाता है कि क्या हुआ।

यह सिंक्रनाइज़ेशन के उद्देश्य के लिए एक सर्वर स्रोत के साथ एक सर्वर स्रोत के साथ बनाया गया था। टेकनेट पर एक संपूर्ण सिंक्रनाइज़ेशन फ्रेम काम है।

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

सीडीसी के विपरीत, तुम कितनी देर तक परिवर्तन डेटाबेस में पिछले पर्ज किए जाने से पहले निर्दिष्ट करें। इसके अलावा, आवेषण और हटाना डेटा रिकॉर्ड नहीं करते हैं। अपडेट केवल रिकॉर्ड करते हैं कि कौन सा क्षेत्र बदल गया है।

चूंकि आप SQL सर्वर स्रोत को किसी अन्य लक्ष्य पर सिंक्रनाइज़ कर रहे हैं, यह ठीक काम करता है। जब तक आप परिवर्तनों को समझने के लिए आवधिक नौकरी नहीं लिखते हैं, तब तक यह ऑडिटिंग के लिए अच्छा नहीं है।

आपको अभी भी उस जानकारी को कहीं भी स्टोर करना होगा।

Description: 
    Enable change tracking 

Cons: 
    Not a good auditing solution 

पहले तीन समाधान आपके ऑडिटिंग के लिए काम करेंगे। मुझे पहला समाधान पसंद है क्योंकि मैं इसे अपने पर्यावरण में बड़े पैमाने पर उपयोग करता हूं।

निष्ठा से

जॉन

प्रस्तुति से कोड स्निपेट (ऑटो डाटाबेस)

-- 
-- 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]; 

** देखो लेखा परीक्षा तालिका के & महसूस **

enter image description here

+0

ग्रेट रीड, अंतर्दृष्टि के लिए धन्यवाद! मैं सिर्फ यह सत्यापित करना चाहता हूं कि मैं आपका कोड स्निपेट समझ गया हूं। आपके पास केवल 1 "लॉग टेबल परिवर्तन" तालिका है, जो प्रत्येक अन्य तालिका से रिकॉर्ड संग्रहीत करेगी और उन तालिकाओं के वास्तविक रिकॉर्ड XML में संग्रहीत हैं? इस तरह आप केवल एक लेखापरीक्षा तालिका है? – Mausimo

+0

ठंडा हिस्सा यह है कि यह 2 आप है।आइए कहें कि आपकी कंपनी कर करता है, आपकी डेटा प्रतिधारण अवधि 7 साल है। आप chg_date पर कई ऑडिट टेबल विभाजन का उपयोग करना चाह सकते हैं। डेटा वेयरहाउसिंग तकनीकों पर मेरी प्रस्तुति देखें। दूसरी तरफ, यदि आप किसी व्यवसाय के लिए आइसक्रीम बेचते हैं, तो आप 2 साल तक रसीदें रख सकते हैं। फिर एक टेबल ठीक हो सकता है। –

+0

ट्रिगर्स के लिए "विपक्ष" में शामिल नहीं होना चाहिए सम्मिलित/अद्यतन/समय हटाएं? मुझे लगता है कि यहां सही निर्णय का हिस्सा लिखने की गति बनाम क्वेरी गति को संतुलित करना है। – Daniel

8

SQL सर्वर (2016+ और Azure) के हाल के संस्करणों में अस्थायी सारणीएं हैं जो पहली श्रेणी सुविधा के रूप में अनुरोध की गई सटीक कार्यक्षमता प्रदान करती हैं। https://docs.microsoft.com/en-us/sql/relational-databases/tables/temporal-tables

माइक्रोसॉफ्ट में कोई भी शायद इस पृष्ठ को पढ़ता है। :)

+1

इसे जोड़ने के लिए धन्यवाद। यह सवाल वास्तव में कुछ समय पहले से था। संयोग से, मैं एक नई परियोजना पर काम कर रहा हूं जिसमें एक समान आवश्यकता है और मैं वास्तव में Azure का उपयोग कर रहा हूं। मैं टेम्पोरल-टेबल्स में देख लूंगा। चीयर्स! – Mausimo