ऐतिहासिक डेटा को कैसे स्टोर करें


162

कुछ सह-कार्यकर्ता और मैं ऐतिहासिक डेटा को स्टोर करने के सर्वोत्तम तरीके पर एक बहस में पड़ गए। वर्तमान में, कुछ प्रणालियों के लिए, मैं ऐतिहासिक डेटा को संग्रहीत करने के लिए एक अलग तालिका का उपयोग करता हूं, और मैं वर्तमान, सक्रिय रिकॉर्ड के लिए एक मूल तालिका रखता हूं। तो, मान लें कि मेरे पास तालिका FOO है। मेरे सिस्टम के तहत, सभी सक्रिय रिकॉर्ड FOO में जाएंगे, और सभी ऐतिहासिक रिकॉर्ड FOO_Hist में जाएंगे। FOO में कई अलग-अलग फील्ड्स को यूजर द्वारा अपडेट किया जा सकता है, इसलिए मैं अपडेट की गई हर चीज का सही हिसाब रखना चाहता हूं। FOO_Hist एक ऑटो-इंक्रीमेंटिंग HIST_ID के अपवाद के साथ FOO के समान सटीक फ़ील्ड रखता है। जब भी FOO अपडेट किया जाता है, मैं FOO_Hist में सम्मिलित विवरण देता हूं:insert into FOO_HIST select * from FOO where id = @id

मेरे सह-कार्यकर्ता का कहना है कि यह खराब डिज़ाइन है क्योंकि मेरे पास ऐतिहासिक कारणों के लिए एक तालिका की सटीक प्रतिलिपि नहीं होनी चाहिए और बस एक और रिकॉर्ड को सक्रिय तालिका में सम्मिलित करना चाहिए जिसमें यह संकेत हो कि यह ऐतिहासिक उद्देश्यों के लिए है।

क्या ऐतिहासिक डेटा भंडारण से निपटने के लिए कोई मानक है? यह मुझे लगता है कि मैं अपने सभी ऐतिहासिक रिकॉर्डों के साथ अपने सक्रिय रिकॉर्ड को एक ही तालिका में शामिल नहीं करना चाहता हूं, यह देखते हुए कि यह एक लाख से अधिक रिकॉर्ड हो सकता है (मैं दीर्घकालिक सोच रहा हूं)।

आप या आपकी कंपनी इसे कैसे संभालती है?

मैं एमएस SQL ​​सर्वर 2008 का उपयोग कर रहा हूं, लेकिन मैं किसी भी DBMS के उत्तर को सामान्य और मनमाना रखना चाहूंगा।

जवाबों:


80

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

यदि आप बारीकी से देखते हैं, तो ऐतिहासिक डेटा की अधिकांश आवश्यकताएं दो श्रेणियों में से एक में आती हैं:

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

  • ऐतिहासिक रिपोर्टिंग: समय के साथ ऐतिहासिक स्थिति, 'जैसे-पर' स्थिति या विश्लेषणात्मक रिपोर्टिंग पर रिपोर्टिंग। ऊपर वर्णित प्रकार की ऑडिट लॉगिंग टेबल्स को क्वेरिंग करके सरल ऐतिहासिक रिपोर्टिंग आवश्यकताओं को पूरा करना संभव हो सकता है। यदि आपके पास अधिक जटिल आवश्यकताएं हैं, तो रिपोर्टिंग के लिए और सीधे ऑपरेटिंग सिस्टम में इतिहास को एकीकृत करने की तुलना में रिपोर्टिंग के लिए डेटा मार्ट को लागू करना अधिक किफायती हो सकता है।

    धीरे-धीरे बदलते आयाम ऐतिहासिक स्थिति को ट्रैक करने और क्वेरी करने के लिए सबसे सरल तंत्र हैं और इतिहास के अधिकांश ट्रैकिंग स्वचालित हो सकते हैं। सामान्य हैंडलर लिखने के लिए कठिन नहीं हैं। आम तौर पर, ऐतिहासिक रिपोर्टिंग में अप-टू-मिनट डेटा का उपयोग नहीं करना पड़ता है, इसलिए एक बैचेड रिफ्रेश मैकेनिज्म सामान्य रूप से ठीक होता है। यह आपके कोर और रिपोर्टिंग सिस्टम आर्किटेक्चर को अपेक्षाकृत सरल रखता है।

यदि आपकी आवश्यकताएं इन दो श्रेणियों में से एक में आती हैं, तो आप शायद अपने परिचालन तंत्र में ऐतिहासिक डेटा संग्रहीत नहीं कर रहे हैं। ऐतिहासिक कार्यक्षमता को एक और उप-प्रणाली में अलग करना संभवतः कम प्रयास होगा और ट्रांजेक्शनल और ऑडिट / रिपोर्टिंग डेटाबेस का उत्पादन करेगा जो अपने इच्छित उद्देश्य के लिए बहुत बेहतर काम करता है।


मुझे लगता है कि मैं देख रहा हूं कि आप क्या कह रहे हैं। इसलिए मैंने अपनी FOO_Hist तालिका के साथ जो किया वह वास्तव में एक ऑडिट टेबल बना। अद्यतन पर ऑडिट तालिका में सम्मिलित करने के लिए एक ट्रिगर का उपयोग करने के बजाय, मैंने सिर्फ कार्यक्रम में एक बयान चलाया। क्या वो सही है?
हारून

6
बहुत ज्यादा। ट्रिगर के साथ ऑडिट लॉगिंग के इस प्रकार करना बेहतर है, हालांकि; ट्रिगर सुनिश्चित करते हैं कि कोई भी परिवर्तन (मैन्युअल डेटा फ़िक्सेस सहित) ऑडिट लॉग में दर्ज किए जाएँ। यदि आपको ऑडिट करने के लिए 10-20 से अधिक टेबल मिले हैं, तो यह ट्रिगर जनरेटर टूल बनाने के लिए संभवत: तेज है। यदि ऑडिट लॉग के लिए डिस्क ट्रैफ़िक एक समस्या है तो आप ऑडिट लॉग टेबल को डिस्क के एक अलग सेट पर रख सकते हैं।
ConcernedOfTunbridgeWells

हां, मैं 100% इससे सहमत हूं। धन्यवाद।
हारून

40

मुझे नहीं लगता कि ऐसा करने का कोई विशेष मानक तरीका है, लेकिन मुझे लगा कि मैं एक संभावित विधि में फेंक दूंगा। मैं ओरेकल और हमारे इन-हाउस वेब एप्लिकेशन फ्रेमवर्क में काम करता हूं जो एक्सएमएल को एप्लिकेशन डेटा स्टोर करने के लिए उपयोग करता है।

हम मास्टर नामक कुछ का उपयोग करते हैं - विस्तार मॉडल जो इसमें सबसे सरल है:

उदाहरण के लिए मास्टर टेबलWidgets अक्सर सिर्फ एक आईडी । अक्सर ऐसा डेटा होगा जो समय के साथ नहीं बदलेगा / ऐतिहासिक नहीं होगा।

विस्तार / इतिहास तालिका उदाहरण के लिए जिसे Widget_Detailsकम से कम कहा जाता है :

  • आईडी - प्राथमिक कुंजी। विस्तार / ऐतिहासिक आईडी
  • MASTER_ID - उदाहरण के लिए 'WIDGET_ID' नामक इस मामले में, यह मास्टर रिकॉर्ड के लिए FK है
  • START_DATETIME - उस डेटाबेस पंक्ति की शुरुआत का संकेत टाइमस्टैम्प
  • END_DATETIME - उस डेटाबेस पंक्ति के अंत का संकेत टाइमस्टैम्प
  • STATUS_CONTROL - एकल चार कॉलम पंक्ति की स्थिति का संकेत दिया। 'C' करंट को इंगित करता है, NULL या 'A' ऐतिहासिक / संग्रहीत होगा। हम इसका उपयोग केवल इसलिए करते हैं क्योंकि हम END_DATETIME NULL होने पर इंडेक्स नहीं कर सकते
  • CREATED_BY_WUA_ID - उस खाते की आईडी संग्रहीत करता है जिसके कारण पंक्ति बनाई गई थी
  • XMLDATA - वास्तविक डेटा संग्रहीत करता है

तो अनिवार्य रूप से, एक इकाई मास्टर में 1 पंक्ति और 1 पंक्ति विस्तार से शुरू होती है। NULL की अंतिम तिथि और 'C' के STATUS_CONTROL वाले विवरण। जब कोई अद्यतन होता है, तो वर्तमान समय के END_DATETIME के ​​लिए वर्तमान पंक्ति को अपडेट किया जाता है और status_control NULL (या 'ए' को प्राथमिकता दी जाती है) पर सेट किया जाता है। एक नई पंक्ति डिटेल टेबल में बनाई गई है, जो अभी भी उसी मास्टर से जुड़ी हुई है, जैसे कि status_control 'C', अपडेट करने वाले व्यक्ति की आईडी और XMLDATA कॉलम में संग्रहीत नया डेटा।

यह हमारे ऐतिहासिक मॉडल का आधार है। Oracle / PL / SQL पैकेज में बनाएं / अपडेट लॉजिक को संभाला जाता है ताकि आप केवल फ़ंक्शन को वर्तमान ID, अपनी उपयोगकर्ता ID और नए XML डेटा से गुजारें और आंतरिक रूप से ऐतिहासिक मॉडल में यह दर्शाने के लिए सभी अपडेट / पंक्तियों को सम्मिलित करें। । प्रारंभ और समाप्ति समय इंगित करता है कि तालिका में उस पंक्ति के लिए सक्रिय है।

भंडारण सस्ता है, हम आम तौर पर डेटा डिलीट नहीं करते हैं और ऑडिट ट्रेल रखना पसंद करते हैं। यह हमें यह देखने की अनुमति देता है कि किसी समय में हमारा डेटा कैसा दिखता था। Status_control = 'C' अनुक्रमित करके या किसी दृश्य का उपयोग करके, अव्यवस्था करना वास्तव में कोई समस्या नहीं है। स्पष्ट रूप से आपके प्रश्नों को ध्यान में रखने की आवश्यकता है जो आपको हमेशा एक रिकॉर्ड के वर्तमान (NULL end_datetime और status_control = 'C') संस्करण का उपयोग करना चाहिए।


हाय क्रिस, अगर आप ऐसा करते हैं, तो आईडी (प्राथमिक कुंजी) को सही बदलना होगा? यदि किसी अन्य व्यक्ति द्वारा उपयोग किया जाता है तो किसी अन्य तालिका के साथ संबंध के बारे में कैसे?
प्रोजो सेप

@ अपने मास्टर टेबल पर आईडी पीके है और आप जिस भी कॉन्सेप्ट के साथ काम कर रहे हैं उसके लिए वैचारिक रूप से "पीके" है। मास्टर के लिए एक ऐतिहासिक संस्करण (जो विस्तार पर एक और कॉलम है) की पहचान करने के लिए डिटेल टेबल पर आईडी पीके है। संबंध बनाते समय आप अक्सर अपनी अवधारणा के सच्चे पीके (यानी आपके मास्टर टेबल पर आईडी या आपके विस्तार पर MASTER_ID कॉलम) का संदर्भ लेंगे और यह सुनिश्चित करने के लिए कि वर्तमान संस्करण प्राप्त कर रहे हैं, STATUS_CONTROL = 'C' का उपयोग करें। वैकल्पिक रूप से आप किसी खास समय में किसी चीज से संबंधित करने के लिए डिटेल आईडी का संदर्भ ले सकते हैं।
क्रिस कैमरन-मिल्स 14

+1 मैंने इस पैटर्न को कई बड़ी परियोजनाओं पर बड़ी सफलता के साथ लागू किया है।
तीन वैल्यू लॉजिक

हम उसी aproach का उपयोग कर रहे हैं। लेकिन अब मैं सोच रहा हूं कि क्या केवल START_DATETIME को संग्रहीत करना बेहतर है और END_DATETIME को स्टोर न करें
27_15

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

15

मुझे लगता है कि आप दृष्टिकोण सही है। ऐतिहासिक तालिका अनुक्रमणिकाओं के बिना मुख्य तालिका की एक प्रति होनी चाहिए, सुनिश्चित करें कि आपके पास तालिका में टाइमस्टैम्प भी अपडेट है।

यदि आप जल्द ही अन्य दृष्टिकोण की कोशिश करते हैं तो आपको समस्याओं का सामना करना पड़ेगा:

  • रखरखाव ओवरहेड
  • चयन में अधिक झंडे
  • प्रश्न मंदी
  • टेबल, इंडेक्स की वृद्धि

7

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


2

डेटा कैप्चर बदलें: https://docs.microsoft.com/en-us/sql/relational-dat about- sql- view sql-server-2017

यह SQL Server 2008 R2 में समर्थित है, यह SQL Server 2008 में समर्थित हो सकता है।


ध्यान दें कि डेटा कैप्चर बदलें डेटा इतिहास के केवल संक्षिप्त संग्रहण के लिए है। देखें एसक्यूएल सर्वर अस्थायी टेबल्स बनाम बदलें डाटा कैप्चर बनाम ट्रैकिंग बदलें
एडवर्ड ब्रे


1

बस एक विकल्प जोड़ना चाहता था जिसे मैंने उपयोग करना शुरू कर दिया क्योंकि मैं एज़्योर एसक्यूएल का उपयोग करता हूं और कई टेबल चीज़ मेरे लिए बहुत बोझिल थी। मैंने अपनी मेज पर एक इंसर्ट / अपडेट / डिलीट ट्रिगर जोड़ा और फिर "JSON AUTO" फ़ीचर का उपयोग करके json में परिवर्तन से पहले / बाद में परिवर्तित कर दिया।

 SET @beforeJson = (SELECT * FROM DELETED FOR JSON AUTO)
SET @afterJson = (SELECT * FROM INSERTED FOR JSON AUTO)

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

मैंने इस लिंक के बारे में यहां से सीखा


0

तुम बस तालिकाओं नहीं विभाजन कर सकते हैं?

"SQL Server 2008 का उपयोग करके विभाजन तालिका और सूचकांक रणनीतियाँ जब एक डेटाबेस तालिका आकार में सैकड़ों गीगाबाइट या उससे अधिक हो जाती है, तो नए डेटा को लोड करना, पुराने डेटा को निकालना और अनुक्रमित बनाए रखना अधिक कठिन हो सकता है। बस तालिका का विशाल आकार। इस तरह के ऑपरेशनों को अधिक समय तक लेने का कारण बनता है। यहां तक ​​कि लोड किए गए या हटाए जाने वाले डेटा को बहुत बड़ा किया जा सकता है, जिससे टेबल पर अव्यवहारिक रूप से INSERT और DELETE संचालन हो सकते हैं। Microsoft SQL Server 2008 डेटाबेस सॉफ़्टवेयर ऐसे ऑपरेशनों को अधिक प्रबंधनीय बनाने के लिए तालिका विभाजन प्रदान करता है। "


हां, मैं तालिकाओं का विभाजन कर सकता हूं, लेकिन क्या यह ऐतिहासिक डेटा के साथ व्यवहार करते समय मानक है? क्या ऐतिहासिक डेटा को सक्रिय डेटा के समान तालिका में शामिल किया जाना चाहिए? ये ऐसे सवाल हैं जिन पर मैं चर्चा करना चाहता था। यह भी मनमाना नहीं है क्योंकि यह SQL Server 2008 से संबंधित है।
एरॉन

0

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


2
क्या JOINएक युगल ऐतिहासिक रिपोर्टों में दो तालिकाओं के लिए अधिक कठिन है या ऐतिहासिक चिंताओं से अवगत होने के लिए हर एक तालिका सम्मिलित / अद्यतन / हटाना को संशोधित करना अधिक कठिन है? दरअसल, ऑडिट लॉग में इतिहास तालिका में वर्तमान डेटा भी शामिल होगा, इसलिए रिपोर्ट में वर्तमान तालिका की भी आवश्यकता नहीं होनी चाहिए।

0

एक अन्य विकल्प परिचालन डेटा को [दैनिक | प्रति घंटा | जो कुछ भी] आधार पर संग्रहीत करना है। अधिकांश डेटाबेस इंजन संग्रह में डेटा की निकासी का समर्थन करते हैं

मूल रूप से, विचार एक अनुसूचित विंडोज या CRON जॉब बनाने का है

  1. परिचालन डेटाबेस में वर्तमान तालिकाओं को निर्धारित करता है
  2. CSV या XML फ़ाइल में हर तालिका से सभी डेटा का चयन करता है
  3. एक ज़िप फ़ाइल में निर्यात किए गए डेटा को संपीड़ित करता है, अधिमानतः आसान संग्रह के लिए फ़ाइल नाम में पीढ़ी के टाइमस्टैम्प के साथ।

कई SQL डेटाबेस इंजन एक उपकरण के साथ आते हैं जिसका उपयोग इस उद्देश्य के लिए किया जा सकता है। उदाहरण के लिए, जब लिनक्स पर MySQL का उपयोग करते हैं, तो निम्न कमांड का उपयोग निष्कर्षण को शेड्यूल करने के लिए एक CRON जॉब में किया जा सकता है:

mysqldump --all-databases --xml --lock-tables=false -ppassword | gzip -c | cat > /media/bak/servername-$(date +%Y-%m-%d)-mysql.xml.gz

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

0

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

ऑडिट (सुरक्षा उद्देश्य) : अपने सभी श्रव्य तालिकाओं के लिए एक सामान्य तालिका का उपयोग करें। मूल्य से पहले और मूल्य क्षेत्रों के बाद कॉलम नाम को स्टोर करने के लिए संरचना को परिभाषित करें।

पुरालेख / ऐतिहासिक : पिछले पते पर नज़र रखने, फ़ोन नंबर आदि जैसे मामलों के लिए एक अलग तालिका बनाने FOO_HIST बेहतर है यदि आप अपने सक्रिय लेन-देन तालिका स्कीमा भविष्य में महत्वपूर्ण रूप से नहीं बदलते हैं (यदि आपकी इतिहास तालिका में समान संरचना है)। यदि आप तालिका के सामान्यीकरण का अनुमान लगाते हैं, तो डेटाटाइप कॉलम को हटाने / हटाने के अलावा, अपने ऐतिहासिक डेटा को xml प्रारूप में संग्रहीत करता है। निम्नलिखित कॉलम (आईडी, दिनांक, स्कीमा संस्करण, XMLData) के साथ एक तालिका परिभाषित करें। यह स्कीमा परिवर्तनों को आसानी से संभाल लेगा। लेकिन आपको xml से निपटना होगा और यह डेटा पुनर्प्राप्ति के लिए जटिलता का स्तर पेश कर सकता है।



0

आप टेबल पर एक भौतिक / अनुक्रमित विचार बना सकते हैं। अपनी आवश्यकता के आधार पर आप विचारों का पूर्ण या आंशिक अद्यतन कर सकते हैं। कृपया mview और लॉग बनाने के लिए इसे देखें। SQL Server में भौतिक विचार कैसे बनाएं?

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