हमारे सिस्टम में हमारे पास मूल कच्चे डेटा वाला एक टेबल है। इस कच्चे डेटा को प्रति घंटा, दैनिक और साप्ताहिक अंतराल (योग, न्यूनतम, प्रत्येक अंतराल के लिए कच्चे मूल्यों का अधिकतम) में सारांशित किया जाता है।
हम 30 दिनों (4 सप्ताह) के लिए कच्चे डेटा, 43 दिनों (6 सप्ताह) के लिए प्रति घंटा, दैनिक 560 दिनों (18 महीने) के लिए प्रतिदिन, साप्ताहिक 10 वर्षों के लिए रखते हैं। हर रात इन चार तालिकाओं को "साफ" किया जाता है और थ्रेसहोल्ड से पुराना डेटा हटा दिया जाता है। प्रति घंटा तालिका में लगभग 30 एम पंक्तियां होती हैं, दैनिक 18 एम पंक्तियां होती हैं। कुछ रिपोर्ट/चार्ट प्रति घंटा डेटा का उपयोग करते हैं, अधिकतर दैनिक डेटा का उपयोग करते हैं। कभी-कभी हमें किसी समस्या की विस्तृत जांच के लिए कच्चे डेटा को देखने की आवश्यकता होती है।
मेरे पास सी ++ में लिखा गया एक समर्पित एप्लिकेशन है, जो सर्वर पर चलता है 24/7 और ~ 200 अन्य सर्वरों से कच्चे डेटा एकत्र करता है और इसे केंद्रीय डेटाबेस में सम्मिलित करता है। आवेदन के अंदर मैं समय-समय पर (हर 10 मिनट) एक संग्रहीत प्रक्रिया को कॉल करता हूं जो सारांशों को फिर से समझता है। यह संग्रहीत प्रक्रिया किसी भी समय अंतिम उपयोगकर्ता द्वारा चलाया जा सकता है, यदि उपयोगकर्ता नवीनतम डेटा देखना चाहता है। आमतौर पर इसे चलाने में लगभग 10 सेकंड लगते हैं, इसलिए आम तौर पर अंतिम उपयोगकर्ता देर से सारांश देखता है। तो, तकनीकी रूप से सर्वर पर एक निर्धारित नौकरी हो सकती है जो हर 10 मिनट में प्रक्रिया चलाती है। जब मैं इसे किसी एप्लिकेशन के माध्यम से करता हूं तो मेरे पास डेटा एकत्र करने वाले अन्य धागे पर बेहतर नियंत्रण होता है। अनिवार्य रूप से, मैं संक्षेप में होने पर नए डेटा को सम्मिलित करने का प्रयास रोकता हूं। लेकिन, केवल स्वतंत्र संग्रहित प्रक्रियाओं का उपयोग करके एक ही प्रभाव प्राप्त करना संभव है।
मेरे मामले में मैं सारांशों का पुनर्मूल्यांकन बल्कि कुशल बना सकता हूं।
चूंकि इस 10 मिनट की विंडो के दौरान डेटाबेस में नया डेटा बहता है, इसलिए मैं कच्ची डेटा सीधे मुख्य तालिका में डालता हूं। कच्चे डेटा बिंदु कभी अपडेट नहीं होते हैं, वे केवल जोड़े जाते हैं (सम्मिलित)।तो, यह कदम सरल और कुशल है। मैं संग्रहित प्रक्रिया का उपयोग टेबल-मूल्य वाले पैरामीटर के साथ करता हूं और एक कॉल में नए डेटा का एक हिस्सा पास करता हूं। इस प्रकार एक पंक्ति में INSERT
कथन में कई पंक्तियां डाली जाती हैं, जो अच्छी है।
सारांश तालिका को दूसरी संग्रहीत प्रक्रिया का उपयोग करके हर 10 मिनट में नए डेटा के साथ अपडेट किया जाता है। मौजूदा पंक्तियों में से कुछ को अद्यतन किया जाना चाहिए, कुछ पंक्तियां जोड़ दी गई हैं। इसे कुशलतापूर्वक करने के लिए मेरे पास मशीन की आईडी, प्रति घंटा दिनांक-समय, दैनिक दिनांक-समय, साप्ताहिक दिनांक-समय कॉलम के साथ एक अलग "स्टेजिंग" तालिका है। चूंकि मैं मुख्य तालिका में कच्चा डेटा डालता हूं, इसलिए मैं इस स्टेजिंग तालिका में प्रभावित मशीन आईडी और प्रभावित समय अंतराल भी डालता हूं।
तो, दो मुख्य संग्रहित प्रक्रियाएं हैं। कई थ्रेड का उपयोग करके 200 रिमोट सर्वर के माध्यम से एप्लिकेशन लूप करता है और एक अनंत लूप में प्रत्येक सर्वर से ताजा डेटा डाउनलोड करता है। जैसे ही कुछ रिमोट सर्वर से डेटा के ताजा बैच को डाउनलोड किया जाता है, पहली संग्रहीत प्रक्रिया को बुलाया जाता है। यह अक्सर होता है। यह प्रक्रिया कच्ची डेटा में कच्चे डेटा के बैच को "स्टेजिंग" तालिका में प्रभावित समय अंतराल की सूची के रूप में सम्मिलित करती है।
कहो, कच्चे आंकड़ों के भेजे बैच इस तरह दिखता है:
ID timestamp raw_value
1 2015-01-01 23:54:45 123
1 2015-01-01 23:57:12 456
1 2015-01-02 00:03:23 789
2 2015-01-02 02:05:21 909
4 पंक्तियों मुख्य तालिका के रूप में (आईडी, टाइमस्टैम्प, मूल्य) में डाला जाता है।
3 पंक्तियों मचान तालिका में डाला जाता है (आम तौर पर एक ही घंटे से टाइमस्टैम्प के साथ मूल्यों का एक बहुत होते हैं, इसलिए मचान तालिका में कच्चे पंक्तियों का एक बहुत है, लेकिन कुछ देखते हैं):
ID hourlytimestamp dailytimestamp weeklytimestamp
1 2015-01-01 23:00:00 2015-01-01 00:00:00 2014-12-29 00:00:00
1 2015-01-02 00:00:00 2015-01-02 00:00:00 2014-12-29 00:00:00
2 2015-01-02 00:00:00 2015-01-02 00:00:00 2014-12-29 00:00:00
ध्यान दें, कि यहां मैं सभी आईडी और टाइमस्टैम्प को अद्वितीय सेट में मिला/मिला/मिला हूं और इस स्टेजिंग टेबल में मूल्य नहीं हैं, इसमें केवल प्रभावित आईडी और समय अंतराल होते हैं (StatsToRecalc
यह स्टेजिंग तालिका है, @ParamRows
पैरामीटर है संग्रहित प्रक्रिया के जिसमें नए डेटा के साथ पंक्तियों का बैच है):
DECLARE @VarStart datetime = '20000103'; -- it is Monday
INSERT INTO dbo.StatsToRecalc
(ID
,PeriodBeginLocalDateTimeHour
,PeriodBeginLocalDateTimeDay
,PeriodBeginLocalDateTimeWeek)
SELECT DISTINCT
TT.[ID],
-- Truncate time to 1 hour.
DATEADD(hour, DATEDIFF(hour, @VarStart, TT.PlaybackStartedLocalDateTime), @VarStart),
-- Truncate time to 1 day.
DATEADD(day, DATEDIFF(day, @VarStart, TT.PlaybackStartedLocalDateTime), @VarStart),
-- Truncate time to 1 week.
DATEADD(day, ROUND(DATEDIFF(day, @VarStart, TT.PlaybackStartedLocalDateTime)/7, 0, 1) * 7, @VarStart)
FROM @ParamRows AS TT;
फिर से कच्चे तालिका में INSERT
सरल है।
तो, 10 मिनट के लिए कई धागे से इस प्रक्रिया का उपयोग करके कच्चे और स्टेजिंग टेबल में कई INSERTS
हैं।
हर 10 मिनट में दूसरी प्रक्रिया जो सारांश को पुन: गणना करती है उसे बुलाया जाता है।
पहली बात यह है करता है एक सौदे शुरू होता है और लेन-देन के अंत तक मचान तालिका ताले:
SELECT @VarCount = COUNT(*)
FROM dbo.StatsToRecalc
WITH (HOLDLOCK)
तो मचान तालिका StatsToRecalc
खाली नहीं है, हम कुछ करने की जरूरत है। चूंकि यह तालिका लॉक है, सभी काम करने वाले धागे हस्तक्षेप नहीं करेंगे और अधिक डेटा जोड़ने से पहले पुनर्मूल्यांकन समाप्त होने तक प्रतीक्षा करेंगे।
इस स्टेजिंग टेबल का उपयोग करके मैं जल्दी से निर्धारित कर सकता हूं कि कौन से घंटों, दिन और हफ्तों के लिए मुझे आईडी को पुन: गणना करने की आवश्यकता है। वास्तविक सारांश गणना MERGE
कथन में की जाती है, जो सभी प्रभावित आईडी और अंतराल को एक बार में संसाधित करती है। मैं तीन MERGEs
को कच्चे डेटा को प्रति घंटा सारांश में समेटने के लिए चलाता हूं, फिर प्रति घंटे प्रतिदिन और फिर साप्ताहिक में। फिर स्टेजिंग टेबल खाली हो जाती है (हर 10 मिनट), इसलिए यह कभी भी बड़ा नहीं होता है।
पहली बार में प्रत्येक MERGE
(उदाहरण के लिए, प्रति घंटा से दैनिक तालिका अद्यतन करने के लिए) आईडी और timestamps की एक सूची है कि पिछले पुनर्गणना के बाद से प्रभावित हुए हैं बनाता है:
WITH
CTE_Changed (ID, PeriodBeginLocalDateTimeDay)
AS
(
SELECT
dbo.StatsToRecalc.ID
, dbo.StatsToRecalc.PeriodBeginLocalDateTimeDay
FROM
dbo.StatsToRecalc
GROUP BY
dbo.StatsToRecalc.ID
,dbo.StatsToRecalc.PeriodBeginLocalDateTimeDay
)
और फिर इस CTE के साथ प्रति घंटा की तालिका संयोजन MERGE
:
MERGE INTO dbo.StatsDay AS Dest
USING
(
SELECT
...
FROM
dbo.StatsHour
INNER JOIN CTE_Changed ON
CTE_Changed.ID = dbo.StatsHour.ID AND
CTE_Changed.PeriodBeginLocalDateTimeDay = dbo.StatsHour.PeriodBeginLocalDateTimeDay
)
...
इस बहुमंज़िला संक्षेप मैं कच्चे में सहायक कॉलम है, प्रति घंटा और दैनिक तालिकाओं के साथ मदद करने के लिए।
2015-01-01 22:00:00
2015-01-01 23:00:00
2015-01-02 00:00:00
2015-01-02 01:00:00
...
, एक घंटे की अर्थात सीमाओं: उदाहरण के लिए, प्रति घंटा की मेज एक स्तंभ PeriodBeginLocalDateTimeHour
जो इस तरह के मूल्यों रखती है। PeriodBeginLocalDateTimeDay
है, जो इस तरह के मूल्यों रखती है::
2015-01-01 00:00:00
2015-01-02 00:00:00
...
, एक दिन अर्थात् सीमाओं उसी समय वहाँ एक दूसरे स्तंभ है कि इन टाइम स्टांप दिन सीमा के लिए "छोटा" शामिल है। दूसरा कॉलम केवल तभी उपयोग किया जाता है जब मैं दिनों में घंटों का योग करता हूं - मुझे फ्लाई पर दिन टाइमस्टैम्प की गणना करने की आवश्यकता नहीं है, बल्कि लगातार अनुक्रमित मानों का उपयोग करें।
मुझे जोड़ना चाहिए, कि मेरे मामले में यह ठीक है अगर उस समर्पित सी ++ एप्लिकेशन थोड़ी देर के लिए नीचे था। इसका मतलब यह है कि डेटा 10 मिनट से अधिक समय तक देरी होगी, लेकिन कुछ भी खो जाएगा नहीं।
आप ऐसा करने के लिए एसक्यूएल सर्वर में एक [निर्धारित नौकरी] (https://msdn.microsoft.com/en-us/library/ms191439.aspx) का उपयोग कर सकते हैं। –
यह आशाजनक लग रहा है, धन्यवाद! आपके व्यापक उत्तर के लिए – Robert