लगातार प्रसंस्करण के दौरान सूचकांक विखंडन


10

SQL सर्वर 2005

मुझे 900M रिकॉर्ड तालिका में 350M रिकॉर्ड के बारे में निरंतर प्रक्रिया करने में सक्षम होना चाहिए। मैं जिस प्रक्रिया को रिकॉर्ड करने के लिए चयन करने के लिए उपयोग कर रहा हूं वह क्वेरी मैं प्रक्रिया के रूप में बुरी तरह से खंडित हो जाती है और मुझे सूचकांक के पुनर्निर्माण के लिए प्रसंस्करण को रोकने की आवश्यकता है। छद्म डेटा मॉडल और क्वेरी ...

/**************************************/
CREATE TABLE [Table] 
(
    [PrimaryKeyId] [INT] IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
    [ForeignKeyId] [INT] NOT NULL,
    /* more columns ... */
    [DataType] [CHAR](1) NOT NULL,
    [DataStatus] [DATETIME] NULL,
    [ProcessDate] [DATETIME] NOT NULL,
    [ProcessThreadId] VARCHAR (100) NULL
);

CREATE NONCLUSTERED INDEX [Idx] ON [Table] 
(
    [DataType],
    [DataStatus],
    [ProcessDate],
    [ProcessThreadId]
);
/**************************************/

/**************************************/
WITH cte AS (
    SELECT TOP (@BatchSize) [PrimaryKeyId], [ProcessThreadId]
    FROM [Table] WITH ( ROWLOCK, UPDLOCK, READPAST )
    WHERE [DataType] = 'X'
    AND [DataStatus] IS NULL
    AND [ProcessDate] < DATEADD(m, -2, GETDATE()) -- older than 2 months
    AND [ProcessThreadId] IS NULL
)
UPDATE cte
SET [ProcessThreadId] = @ProcessThreadId;

SELECT * FROM [Table] WITH ( NOLOCK )
WHERE [ProcessThreadId] = @ProcessThreadId;
/**************************************/

डेटा सामग्री ...
जबकि स्तंभ [डेटाटाइप] एक CHAR (1) के रूप में टाइप किया जाता है, शेष रिकॉर्ड 'ए' के ​​साथ 'एक्स' के बराबर सभी रिकॉर्ड का लगभग 35%।
केवल उन अभिलेखों में जहां [DataType] 'X' के बराबर होता है, लगभग 10% में NOT NULL [DataStatus] मान होगा।

[ProcessDate] और [ProcessThreadId] कॉलम को संसाधित किए गए हर रिकॉर्ड के लिए अपडेट किया जाएगा।
[DataType] कॉलम अपडेट किया गया है (लगभग 10% समय में 'X' को 'A' में बदल दिया गया है)।
[DataStatus] कॉलम 1% से कम समय में अपडेट किया जाता है।

अभी के लिए मेरा समाधान अलग प्रसंस्करण तालिका में संसाधित करने के लिए सभी रिकॉर्डों की प्राथमिक कुंजी का चयन करना है। मैं कुंजी को हटाता हूं क्योंकि मैं उन्हें संसाधित करता हूं ताकि सूचकांक के टुकड़े के रूप में मैं कम रिकॉर्ड के साथ काम कर रहा हूं।

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

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


एक विचार भी: आपका सूचकांक गलत क्रम प्रतीत होता है: यह सबसे कम से कम चयनात्मक होना चाहिए। तो ProcessThreadId, ProcessDate, DataStatus, DataType शायद?
gbn

हमने अपनी चैट में इसका विज्ञापन किया है। बहुत अच्छा सवाल है। chat.stackexchange.com/rooms/179/the-heap
gbn

मैंने चयन का अधिक सटीक प्रतिनिधित्व करने के लिए क्वेरी को अद्यतन किया। मैं इसे चलाने वाले कई समवर्ती धागे। मैंने सेलेक्टिव ऑर्डर की सिफारिश नोट कर ली है। धन्यवाद।
क्रिस गैलुची

@ChrisGallucci आप कर सकते हैं ... चैट करने के लिए आओ ...
JNK

जवाबों:


4

आप जो कर रहे हैं वह एक कतार के रूप में एक तालिका का उपयोग कर रहा है। आपका अद्यतन dequeue पद्धति है। लेकिन मेज पर संकुल सूचकांक कतार के लिए एक खराब विकल्प है। क्यू के रूप में तालिकाओं का उपयोग करना वास्तव में टेबल डिजाइन पर काफी कठोर आवश्यकताओं को लागू करता है। आपके क्लस्टर किए गए इंडेक्स में इस मामले में होने की संभावना के कारण डीक्यू ऑर्डर होना चाहिए ([DataType], [DataStatus], [ProcessDate])। आप प्राथमिक कुंजी को एक गैर-स्पष्ट बाधा के रूप में लागू कर सकते हैं । गैर-संकुलित सूचकांक Idxको गिराएं, क्योंकि क्लस्टर कुंजी इसकी भूमिका लेती है।

पहेली का एक अन्य महत्वपूर्ण टुकड़ा प्रसंस्करण के दौरान पंक्ति के आकार को स्थिर रखना है। आपने घोषित किया है ProcessThreadIdकि एक VARCHAR(100)पंक्ति बढ़ती है और सिकुड़ती है, जैसा कि 'संसाधित' किया जा रहा है क्योंकि फ़ील्ड मान NULL से गैर-शून्य में बदल जाता है। पंक्ति पर यह बढ़ने और सिकुड़ने वाला पैटर्न पृष्ठ विभाजन और विखंडन का कारण बनता है। मैं संभवतः एक थ्रेड आईडी की कल्पना नहीं कर सकता जो कि 'वर्कर (100)' है। निश्चित लंबाई प्रकार का उपयोग करें, शायद ए INT

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

/**************************************/
CREATE TABLE [Table] 
(
    [PrimaryKeyId] [INT] IDENTITY(1,1) NOT NULL PRIMARY KEY NONCLUSTERED,
    [ForeignKeyId] [INT] NOT NULL,
    /* more columns ... */
    [DataType] [CHAR](1) NOT NULL,
    [DataStatus] [DATETIME] NULL,
    [ProcessDate] [DATETIME] NOT NULL,
    [ProcessThreadId] INT NULL
);

CREATE CLUSTERED INDEX [Cdx] ON [Table] 
(
    [DataType],
    [DataStatus],
    [ProcessDate]
);
/**************************************/

declare @BatchSize int, @ProcessThreadId int;

/**************************************/
WITH cte AS (
    SELECT TOP (@BatchSize) [PrimaryKeyId], [ProcessThreadId] , ... more columns 
    FROM [Table] WITH ( ROWLOCK, UPDLOCK, READPAST )
    WHERE [DataType] = 'X'
    AND [DataStatus] IS NULL
    AND [ProcessDate] < DATEADD(m, -2, GETDATE()) -- older than 2 months
    AND [ProcessThreadId] IS NULL
)
UPDATE cte
SET [ProcessThreadId] = @ProcessThreadId
OUTPUT DELETED.[PrimaryKeyId] , ... more columns ;
/**************************************/

इसके अलावा मैं एक अलग, संग्रह, तालिका में सफलतापूर्वक संसाधित वस्तुओं को स्थानांतरित करने पर विचार करूंगा। आप चाहते हैं कि आपकी कतार तालिका शून्य आकार के पास मँडराए, तो आप नहीं चाहते कि वे बढ़ें क्योंकि वे अनावश्यक पुरानी प्रविष्टियों से 'इतिहास' को बनाए रखते हैं। आप [ProcessDate]एक विकल्प के रूप में विभाजन पर भी विचार कर सकते हैं (अर्थात। एक वर्तमान सक्रिय विभाजन जो कतार के रूप में कार्य करता है और NULL ProcessDate के साथ प्रविष्टियों को संग्रहीत करता है, और सब कुछ गैर-शून्य के लिए एक और विभाजन होता है। या गैर-शून्य के लिए कई विभाजन यदि आप कार्यकुशलता लागू करना चाहते हैं। हटाए गए (स्विच आउट) डेटा के लिए जो अनिवार्य प्रतिधारण अवधि पार कर गया है। यदि चीजें गर्म होती हैं तो आप इसके अलावा विभाजन कर सकते हैं[DataType] यदि इसके पास पर्याप्त चयनात्मकता है, लेकिन यह डिज़ाइन वास्तव में जटिल होगा क्योंकि इसे निरंतर कम्प्यूटेड कॉलम (एक समग्र स्तंभ जो एक साथ चमकता है [DataType] और [ProcessingDate]) द्वारा विभाजन की आवश्यकता होती है।


3

मैं खेतों ProcessDateऔर Processthreadidखेतों को दूसरी तालिका में ले जाकर शुरू करूंगा ।

अभी, इस विस्तृत विस्तृत अनुक्रमणिका से आपके द्वारा चुनी गई प्रत्येक पंक्ति को भी अद्यतन करने की आवश्यकता है।

यदि आप उन दो फ़ील्ड को किसी अन्य तालिका में ले जाते हैं, तो मुख्य टेबल पर आपकी अपडेट वॉल्यूम 90% कट जाती है, जिसे अधिकांश विखंडन का ध्यान रखना चाहिए।

नई तालिका में आपके पास अभी भी विखंडन होगा, लेकिन एक संकीर्ण तालिका पर बहुत कम डेटा के साथ प्रबंधन करना आसान होगा।


यह और शारीरिक रूप से [DataType] पर आधारित डेटा को विभाजित करना मुझे वह मिलना चाहिए जहां मुझे होना चाहिए। मैं इस समय इस डिजाइन (वास्तव में डिजाइन) के चरण में हूं, इसलिए मुझे इस बदलाव का परीक्षण करने का मौका मिलने से पहले कुछ समय होगा।
क्रिस गेलुची
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.