कैसे संस्करण एक डेटाबेस में एक रिकॉर्ड को नियंत्रित करने के लिए


176

मान लीजिए कि डेटाबेस में मेरा एक रिकॉर्ड है और व्यवस्थापक और सामान्य उपयोगकर्ता दोनों अपडेट कर सकते हैं।

किसी को भी एक अच्छा दृष्टिकोण / वास्तुकला का सुझाव दे सकते हैं कि इस तालिका में हर परिवर्तन को कैसे नियंत्रित किया जाए ताकि रिकॉर्ड को पिछले संशोधन में रोलबैक करना संभव हो।

जवाबों:


164

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

फिर, मैं एक FOO_HISTORYटेबल बनाऊंगा। इसमें FOOतालिका के सभी कॉलम हैं । प्राथमिक कुंजी FOO प्लस एक रिविजननंबर कॉलम के समान है। से एक विदेशी कुंजी FOO_HISTORYहै FOO। आप संशोधन से संबंधित कॉलम जैसे कि UserId और RevisionDate भी जोड़ सकते हैं। सभी *_HISTORYतालिका में (यानी एक ओरेकल अनुक्रम या समकक्ष से) बढ़ते-बढ़ते फैशन में पुनरीक्षण करें । एक सेकंड में केवल एक परिवर्तन होने का भरोसा न करें (यानी RevisionDateप्राथमिक कुंजी में मत डालें )।

अब, हर बार जब आप अपडेट करते हैं FOO, तो अपडेट करने से पहले आप पुराने मूल्यों को सम्मिलित करते हैं FOO_HISTORY। आप इसे अपने डिजाइन में कुछ मौलिक स्तर पर करते हैं ताकि प्रोग्रामर गलती से इस कदम को याद न कर सकें।

यदि आप किसी पंक्ति को हटाना चाहते FOOहैं तो आपके पास कुछ विकल्प हैं। या तो सभी इतिहास को कैस्केड करें और हटाएं, या FOOहटाए गए रूप में फ़्लैग करके तार्किक हटाएं करें ।

यह समाधान अच्छा है जब आप वर्तमान मूल्यों में बड़े पैमाने पर रुचि रखते हैं और केवल इतिहास में कभी-कभी। यदि आपको हमेशा इतिहास की आवश्यकता है तो आप प्रभावी शुरुआत और समाप्ति तिथियां डाल सकते हैं और सभी रिकॉर्ड FOOअपने आप में रख सकते हैं । हर क्वेरी को फिर उन तारीखों को जांचना होगा।


1
यदि आपका डेटा एक्सेस लेयर सीधे समर्थन नहीं करता है, तो आप डेटाबेस ट्रिगर्स के साथ ऑडिट टेबल अपडेट कर सकते हैं। इसके अलावा, ट्रिगर्स बनाने के लिए एक कोड जनरेटर का निर्माण करना मुश्किल नहीं है जो सिस्टम डेटा शब्दकोश से आत्मनिरीक्षण का उपयोग करता है।
कंसर्नडऑफटुनब्रिजवेल्स

44
मैं सलाह देता हूं कि आप वास्तव में नया डेटा डालें , पिछले नहीं, इसलिए इतिहास तालिका में सभी डेटा हैं। हालाँकि यह रीडायंडेंट डेटा संग्रहीत करता है, यह ऐतिहासिक डेटा की आवश्यकता होने पर दोनों तालिकाओं में खोज से निपटने के लिए आवश्यक विशेष मामलों को समाप्त कर देता है।
Nerdfest

6
व्यक्तिगत रूप से मैं कुछ भी हटाने की सलाह नहीं दूंगा (इसे एक विशिष्ट हाउसकीपिंग गतिविधि के लिए सुरक्षित रखें) और "एक्शन टाइप" कॉलम में यह निर्दिष्ट करने के लिए है कि क्या यह सम्मिलित / अद्यतन / हटाना है। डिलीट के लिए आप पंक्ति को सामान्य रूप से कॉपी करते हैं, लेकिन एक्शन टाइप कॉलम में "डिलीट" करें।
नील बरनवेल

3
@Hydrargyrum एक तालिका जिसमें वर्तमान मान हैं, ऐतिहासिक तालिका के दृश्य से बेहतर प्रदर्शन करेगा। आप वर्तमान मानों को संदर्भित करने वाली विदेशी कुंजियों को भी परिभाषित करना चाह सकते हैं।
डब्ल्यूडब्ल्यू।

2
There is a foreign key from FOO_HISTORY to FOO': बुरा विचार, मैं इतिहास को बदले बिना फू से रिकॉर्ड हटाना चाहूंगा। इतिहास तालिका को सामान्य उपयोग में ही सम्मिलित किया जाना चाहिए।
जैसन

46

मुझे लगता है कि आप डेटाबेस रिकॉर्ड की सामग्री को संस्करण के लिए देख रहे हैं (जैसा कि स्टैकऑवरफ़्लो तब करता है जब कोई प्रश्न / उत्तर संपादित करता है)। एक अच्छा प्रारंभिक बिंदु कुछ डेटाबेस मॉडल को देख सकता है जो संशोधन ट्रैकिंग का उपयोग करता है ।

सबसे अच्छा उदाहरण जो दिमाग में आता है वह है विकिपीडिया इंजन मीडियाविकि। यहां डेटाबेस आरेख की तुलना करें , विशेष रूप से संशोधन तालिका

आप किन तकनीकों का उपयोग कर रहे हैं, इसके आधार पर, आपको कुछ अच्छे अंतर / मर्ज एल्गोरिदम खोजने होंगे।

.NET के लिए इस प्रश्न की जाँच करें


30

बीआई की दुनिया में, आप एक आरंभ और एंडडेट को उस तालिका में जोड़कर इसे पूरा कर सकते हैं जिसे आप संस्करण बनाना चाहते हैं। जब आप तालिका में पहला रिकॉर्ड सम्मिलित करते हैं, तो प्रारंभडेट पॉपुलेटेड होता है, लेकिन एंडडेट शून्य है। जब आप दूसरा रिकॉर्ड डालते हैं, तो आप दूसरे रिकॉर्ड के प्रारंभ के साथ पहले रिकॉर्ड के एंडेड को भी अपडेट करते हैं।

जब आप वर्तमान रिकॉर्ड देखना चाहते हैं, तो आप उसे चुनें जहां एंडडेट अशक्त है।

इसे कभी-कभी टाइप 2 धीरे-धीरे बदलते आयाम कहा जाता है । TupleVersioning भी देखें


क्या इस दृष्टिकोण का उपयोग करके मेरी तालिका काफी बड़ी नहीं होगी?
नील्स बोसमा

1
हां, लेकिन आप तालिका का अनुक्रमण और / या विभाजन करके इससे निपट सकते हैं। इसके अलावा, वहाँ केवल बड़े टेबल के एक छोटे से मुट्ठी भर होगा। अधिकांश बहुत छोटा होगा।
ConcernedOfTunbridgeWells 11

अगर मैं यहाँ केवल गिरावट नहीं है, तो यह है कि यह परिवर्तन प्रति सेकंड एक बार सही है?
१६:19

@pimbrouwers हाँ, यह अंततः फ़ील्ड्स की सटीकता और उन्हें पॉप करने वाले फ़ंक्शन पर निर्भर करता है।
डेव नीली

9

SQL 2008 में अपग्रेड करें।

SQL 2008 में, SQL बदलें ट्रैकिंग का उपयोग करने का प्रयास करें। टाइमस्टैम्पिंग और tombstone कॉलम हैक्स के बजाय, आप अपने डेटाबेस में डेटा पर नज़र रखने के लिए इस नई सुविधा का उपयोग कर सकते हैं।

MSDN SQL 2008 ट्रैकिंग बदलें


7

बस यह जोड़ना चाहते थे कि इस समस्या का एक अच्छा समाधान एक टेम्पोरल डेटाबेस का उपयोग करना है । कई डेटाबेस विक्रेता इस सुविधा को बॉक्स से बाहर या एक एक्सटेंशन के माध्यम से प्रदान करते हैं। मैंने PostgreSQL के साथ अस्थायी तालिका एक्सटेंशन का सफलतापूर्वक उपयोग किया है, लेकिन दूसरों के पास भी है। जब भी आप डेटाबेस में कोई रिकॉर्ड अपडेट करते हैं, डेटाबेस उस रिकॉर्ड के पिछले संस्करण को भी पकड़ लेता है।


6

दो विकल्प:

  1. एक हिस्ट्री टेबल रखें - जब भी ओरिजिनल अपडेट किया जाए तो इस हिस्ट्री टेबल में पुराना डेटा डालें।
  2. ऑडिट टेबल - मूल्यों से पहले और बाद में स्टोर करें - ऑडिट टेबल में संशोधित कॉलम के साथ-साथ अन्य जानकारी जैसे कि अपडेट और कब।

5

आप SQL ट्रिगर के माध्यम से SQL टेबल पर ऑडिटिंग कर सकते हैं। एक ट्रिगर से आप 2 विशेष तालिकाओं ( सम्मिलित और हटाए गए ) तक पहुंच सकते हैं । इन तालिकाओं में सटीक पंक्तियाँ होती हैं जिन्हें हर बार तालिका के अद्यतन होने के बाद डाला या हटाया जाता है। ट्रिगर एसक्यूएल में आप इन संशोधित पंक्तियों को ले सकते हैं और उन्हें ऑडिट टेबल में डाल सकते हैं। इस दृष्टिकोण का अर्थ है कि आपका ऑडिटिंग प्रोग्रामर के लिए पारदर्शी है; उन्हें या किसी भी कार्यान्वयन ज्ञान से कोई प्रयास की आवश्यकता नहीं है।

इस दृष्टिकोण का जोड़ा बोनस यह है कि ऑडिटिंग चाहे आपके डेटा एक्सेस DLLs के माध्यम से या मैन्युअल SQL क्वेरी के माध्यम से sql कार्रवाई हुई हो; (जैसा कि ऑडिटिंग सर्वर पर ही किया जाता है)।


3

आप यह नहीं कहते कि डेटाबेस क्या है, और मैं इसे पोस्ट टैग में नहीं देखता। यदि यह ओरेकल के लिए है, तो मैं डिज़ाइनर में बनाए गए दृष्टिकोण की सिफारिश कर सकता हूं: जर्नल टेबल का उपयोग करें । यदि यह किसी अन्य डेटाबेस के लिए है, तो ठीक है, मैं मूल रूप से उसी तरह की सिफारिश करता हूं, भी ...

जिस तरह से यह काम करता है, यदि आप इसे दूसरे डीबी में बदलना चाहते हैं, या शायद अगर आप इसे समझना चाहते हैं, तो यह है कि एक तालिका के लिए एक छाया तालिका भी बनाई गई है, बस एक सामान्य डेटाबेस तालिका, उसी फ़ील्ड चश्मा के साथ , प्लस कुछ अतिरिक्त फ़ील्ड: जैसे कि पिछली बार क्या कार्रवाई की गई थी (स्ट्रिंग, विशिष्ट मान "INS" डालने के लिए, अद्यतन के लिए "UPD" और हटाने के लिए "DEL"), कार्रवाई कब हुई, और उपयोगकर्ता आईडी किसने की, इसके लिए डेटाटाइम यह।

ट्रिगर्स के माध्यम से, तालिका में किसी भी पंक्ति के लिए हर क्रिया नए मूल्यों के साथ जर्नल तालिका में एक नई पंक्ति सम्मिलित करती है, क्या कार्रवाई की गई, कब, और किस उपयोगकर्ता द्वारा की गई। आप कभी भी कोई पंक्तियाँ नहीं हटाते हैं (कम से कम पिछले कुछ महीनों से नहीं)। हां यह बड़ी, आसानी से लाखों पंक्तियों में विकसित होगी, लेकिन आप किसी भी समय किसी भी रिकॉर्ड के लिए मूल्य को आसानी से ट्रैक कर सकते हैं क्योंकि जर्नलिंग शुरू हो गई है या पुरानी पत्रिका पंक्तियों को अंतिम रूप दिया गया है, और जिसने अंतिम परिवर्तन किया है।

ओरेकल में आपको जो कुछ भी चाहिए वह स्वचालित रूप से SQL कोड के रूप में उत्पन्न होता है, आपको बस इसे संकलित / चलाना है; और यह एक बुनियादी CRUD आवेदन (वास्तव में केवल "आर") के साथ आता है इसका निरीक्षण करने के लिए।


2

मैं भी यही काम कर रहा हूं। मैं पाठ योजनाओं के लिए एक डेटाबेस बना रहा हूं। इन योजनाओं में परमाणु परिवर्तन संस्करण लचीलापन की आवश्यकता है। दूसरे शब्दों में, प्रत्येक परिवर्तन, चाहे कितना छोटा हो, पाठ योजनाओं के लिए अनुमति दी जानी चाहिए, लेकिन पुराने संस्करण को भी बरकरार रखने की आवश्यकता है। इस तरह, पाठ निर्माता पाठ योजनाओं को संपादित कर सकते हैं जबकि छात्र उनका उपयोग कर रहे हैं।

जिस तरह से यह काम करेगा वह यह है कि एक बार एक छात्र ने एक पाठ किया है, उनके परिणाम उनके द्वारा पूर्ण किए गए संस्करण से जुड़े हैं। यदि कोई परिवर्तन किया जाता है, तो उनका परिणाम हमेशा उनके संस्करण की ओर संकेत करेगा।

इस तरह, यदि कोई पाठ मानदंड हटा दिया जाता है या स्थानांतरित कर दिया जाता है, तो उनके परिणाम नहीं बदलेंगे।

जिस तरह से मैं वर्तमान में यह कर रहा हूं वह एक तालिका में सभी डेटा को संभालने से है। आम तौर पर मेरे पास सिर्फ एक आईडी फ़ील्ड होता है, लेकिन इस प्रणाली के साथ, मैं एक आईडी और एक सब_ड का उपयोग कर रहा हूं। सब_ड हमेशा अपडेट और डिलीट के माध्यम से पंक्ति के साथ रहता है। आईडी को ऑटो-इंक्रीज किया गया है। सबक योजना सॉफ्टवेयर नवीनतम सब_ड से लिंक होगा। छात्र रिजल्ट आईडी से लिंक करेंगे। मैंने बदलाव के समय ट्रैकिंग के लिए टाइमस्टैम्प को भी शामिल किया है, लेकिन संस्करण को संभालना आवश्यक नहीं है।

एक बार मैं इसे बदल सकता हूं, एक बार मैंने इसका परीक्षण किया है, क्या मैं पहले उल्लेख किए गए एंडेड नल विचार का उपयोग कर सकता हूं। मेरे सिस्टम में, नवीनतम संस्करण को खोजने के लिए, मुझे अधिकतम (आईडी) ढूंढना होगा। दूसरी प्रणाली सिर्फ एंडेट = शून्य की तलाश में है। सुनिश्चित नहीं हैं कि लाभ एक और दिनांक फ़ील्ड होने पर।

मेरे दो सेंट।


2

जबकि @ डब्लू डब्लू। उत्तर एक अच्छा जवाब है एक और तरीका है कि एक संस्करण कॉलम बनाएं और अपने सभी संस्करणों को एक ही तालिका में रखें।

एक टेबल अप्रोच के लिए आप या तो:

  • नवीनतम अला वर्ड प्रेस को इंगित करने के लिए एक ध्वज का उपयोग करें
  • या संस्करण की तुलना में अधिक गंदा है outer join

outer joinसंशोधन संख्याओं का उपयोग करते हुए विधि का एक उदाहरण SQL है:

SELECT tc.*
FROM text_content tc
LEFT OUTER JOIN text_content mc ON tc.path = mc.path
AND mc.revision > tc.revision
WHERE mc.revision is NULL 
AND tc.path = '/stuff' -- path in this case is our natural id.

बुरी खबर यह है कि उपरोक्त की आवश्यकता है outer joinऔर बाहरी जुड़ाव धीमा हो सकता है। अच्छी खबर यह है कि नई प्रविष्टियां बनाना सैद्धांतिक रूप से सस्ता है, क्योंकि आप इसे एक लेनदेन के साथ ऑपरेशन में कर सकते हैं (यह मानते हुए कि आपका डेटाबेस परमाणु है)।

उदाहरण के लिए एक नया संशोधन '/stuff'हो सकता है:

INSERT INTO text_content (id, path, data, revision, revision_comment, enabled, create_time, update_time)
(
SELECT
(md5(random()::text)) -- {id}
, tc.path
, 'NEW' -- {data}
, (tc.revision + 1)
, 'UPDATE' -- {comment}
, 't' -- {enabled}
, tc.create_time
, now() 
FROM text_content tc
LEFT OUTER JOIN text_content mc ON tc.path = mc.path
AND mc.revision > tc.revision
WHERE mc.revision is NULL 
AND tc.path = '/stuff' -- {path}
)

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

ध्वज दृष्टिकोण और इतिहास तालिका के दृष्टिकोण को सम्मिलित / अद्यतन करने के लिए दो पंक्तियों की आवश्यकता होती है ।

outer joinसंशोधन संख्या दृष्टिकोण के साथ अन्य लाभ यह है कि आप हमेशा ट्रिगर के साथ बाद में एकाधिक तालिका दृष्टिकोण के लिए रिफ्लेक्टर कर सकते हैं क्योंकि आपका ट्रिगर आवश्यक रूप से उपरोक्त जैसा कुछ करना चाहिए।


2

आलोक ने Audit tableऊपर सुझाव दिया , मैं इसे अपनी पोस्ट में समझाना चाहूंगा।

मैंने अपने प्रोजेक्ट पर इस स्कीमा-लेस, सिंगल टेबल डिज़ाइन को अपनाया।

स्कीमा:

  • आईडी - इंटीग्रेटर ऑटो निरीक्षण
  • उपयोगकर्ता नाम - STRING
  • tablename - STRING
  • oldvalue - पाठ / JSON
  • newvalue - पाठ / JSON
  • बनाया - डेटाटाइम

यह तालिका एक ही स्थान पर सभी अभिलेखों के लिए एक ही बार में संपूर्ण वस्तु इतिहास के साथ ऐतिहासिक रिकॉर्ड रख सकती है। यह तालिका ट्रिगर्स / हुक का उपयोग करके पॉपुलेटेड हो सकती है जहां डेटा बदलता है, लक्ष्य पंक्ति के पुराने और नए मान स्नैपशॉट संग्रहीत करता है।

इस डिजाइन के साथ पेशेवरों:

  • इतिहास प्रबंधन के लिए तालिकाओं की कम संख्या।
  • प्रत्येक पंक्ति पुरानी और नई अवस्था के पूर्ण स्नैपशॉट।
  • प्रत्येक तालिका पर खोज करना आसान है।
  • तालिका द्वारा विभाजन बना सकते हैं।
  • प्रति तालिका डेटा प्रतिधारण नीति को परिभाषित कर सकते हैं।

इस डिजाइन के साथ विपक्ष:

  • डेटा का आकार बड़ा हो सकता है, अगर सिस्टम में बार-बार बदलाव होते हैं।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.