2010-09-04 22 views
29

एक मेज है कि एक कतार के रूप में काम कर रहा है यह देखते हुए के साथ एक डीबी कतार के रूप में एसक्यूएल सर्वर का उपयोग करना, कैसे मैं सबसे अच्छा तो यह है कि तालिका/प्रश्नों कॉन्फ़िगर कर सकते हैं कतार समवर्ती से अनेक ग्राहकों प्रक्रिया?कई ग्राहकों

उदाहरण के लिए, नीचे दी गई तालिका एक आदेश है कि एक कार्यकर्ता संसाधित करना होगा इंगित करता है। जब कार्यकर्ता किया जाता है, तो यह संसाधित मूल्य को सत्य पर सेट करेगा।

| ID | COMMAND | PROCESSED | 
| 1 | ...  | true  | 
| 2 | ...  | false  | 
| 3 | ...  | false  | 

ग्राहकों से एक आदेश प्राप्त तो जैसे पर काम करने दे सकता है:

select top 1 COMMAND 
from EXAMPLE_TABLE 
with (UPDLOCK, ROWLOCK) 
where PROCESSED=false; 

हालांकि, अगर एक से अधिक कार्यकर्ता हैं, प्रत्येक आईडी = 2 के साथ पंक्ति पाने के लिए कोशिश करता है। केवल पहले निराशावादी ताला मिलेगा, बाकी इंतजार करेंगे। फिर उनमें से एक पंक्ति 3, आदि मिल जाएगा

क्या जानकारी/विन्यास प्रत्येक कार्यकर्ता ग्राहक समवर्ती उन पर प्रत्येक एक अलग पंक्ति और काम पाने के लिए अनुमति होगी?

संपादित करें:

कई जवाब एक में प्रक्रिया राज्य रिकॉर्ड करने के लिए मेज खुद का उपयोग कर में बदलाव का सुझाव दें। मैंने सोचा कि यह एक लेनदेन के भीतर संभव नहीं होगा। (अर्थात, क्या राज्य को अद्यतन करने, अगर कोई अन्य कार्यकर्ता इसे देखेंगे जब तक TXN के लिए प्रतिबद्ध है की बात है?) शायद सुझाव है:

# start transaction 
update to 'processing' 
# end transaction 
# start transaction 
process the command 
update to 'processed' 
# end transaction 

इस तरह से लोगों को आमतौर पर इस समस्या दृष्टिकोण है? ऐसा लगता है कि यदि संभव हो तो डीबी द्वारा समस्या को बेहतर तरीके से संभाला जाएगा।

+0

डुप्लिकेट ... .. –

+3

कृपया मुझे मूल पर इंगित करें, क्योंकि एसओ ने एक डुप्ली की सिफारिश नहीं की थी। – Synesso

+2

माइक्रोसॉफ्ट मैसेज क्व्यूइंग (एमएसएमक्यू) के रूप में किसी भी विंडोज सर्वर के लिए पहले से ही उपलब्ध होने पर यह सारी कार्यक्षमता फिर से बनाने की सभी परेशानी क्यों हो रही है ?? उपयोग करें जो उपलब्ध है - लगातार पहिया का पुन: आविष्कार न करें! –

उत्तर

39

मैं सुझाव है कि आप Using tables as Queues पर जाने। उचित रूप से कार्यान्वित कतार हजारों समवर्ती उपयोगकर्ताओं और सेवा को प्रति मिनट 1/2 मिलियन एनक्यू/डेक्यू ऑपरेशंस के रूप में उच्च संभाल सकती है। एसक्यूएल सर्वर 2005 तक समाधान बोझिल था और एक ही लेनदेन में SELECT और UPDATE मिश्रण मिला और जीबीएन द्वारा लिखे गए लेख में लॉक संकेतों का सही मिश्रण दें। Luckly आउटपुट खंड के आगमन के साथ SQL सर्वर 2005 के बाद से, एक और अधिक सुरुचिपूर्ण समाधान उपलब्ध है, और अब MSDN उपयोग करने की सलाह OUTPUT clause:

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

मूल रूप से वहाँ पहेली के 3 भागों आप एक अत्यधिक समवर्ती ढंग से काम करने के लिए इस के लिए आदेश में सही पाने के लिए की जरूरत है:

1) आपको परमाणु रूप से डेक्यू करने की आवश्यकता है।

with CTE as (
    SELECT TOP(1) COMMAND, PROCESSED 
    FROM TABLE WITH (READPAST) 
    WHERE PROCESSED = 0) 
UPDATE CTE 
    SET PROCESSED = 1 
    OUTPUT INSERTED.*; 

2) आप चाहिए: आप किसी भी बंद कर दिया पंक्तियों skipp जहां OUTPUT खंड खेलने में आता है पंक्ति खोजने के लिए, और यह निशान के रूप में एक, परमाणु ऑपरेशन में 'dequeued', और यह वह जगह है PROCESSED कॉलम पर बाएं सबसे क्लस्टर इंडेक्स कुंजी के साथ अपनी तालिका को ढांचा बनाएं। यदि ID प्राथमिक कुंजी का उपयोग किया गया था, तो उसे क्लस्टर कुंजी में दूसरे कॉलम के रूप में ले जाएं। बहस ID स्तंभ पर एक गैर-संकुल कुंजी रखने के लिए है कि क्या खुला है, लेकिन मैं दृढ़ता से नहीं कतारों से अधिक किसी भी माध्यमिक गैर क्लस्टर अनुक्रमित होने के पक्ष में:

CREATE CLUSTERED INDEX cdxTable on TABLE(PROCESSED, ID); 

3) आपके द्वारा इस तालिका क्वेरी नहीं चाहिए किसी अन्य माध्यम से लेकिन डेक्यू द्वारा। पीक संचालन करने के लिए कोशिश कर रहा है या तालिका का उपयोग करने के लिए दोनों एक कतार और एक दुकान के रूप में के रूप में होगा बहुत संभावना गतिरोध के लिए नेतृत्व और नाटकीय रूप से प्रवाह क्षमता धीमी हो जाएगी कोशिश कर रहा।

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

+0

वह ["पंक्तियों के रूप में सारणी का उपयोग करना"] (http : //rusanu.com/2010/03/26/using-tables-as-queues/) आलेख उन लोगों के लिए शुद्ध सोना है जिन्हें सेवा ब्रोकर (उदाहरण के लिए लंबित कतार) के लिए उपयुक्त कतार लागू नहीं करना है। धन्यवाद मैंग। –

+0

संदेश_हैंडर रोलबैक (उसी लेनदेन के भीतर) कब करना चाहता है जब बाद में संसाधित करने के लिए लंबित संदेश को फिर से निर्धारित किया जाए? – dariol

+0

@ डारियो-जी: आप जानबूझकर संदेश प्रसंस्करण में रोलबैक नहीं कर सकते हैं। –

0

बल्कि प्रसंस्कृत आप किसी पूर्णांक इस्तेमाल कर सकते हैं के लिए एक बूलियन मान का उपयोग कर आदेश की स्थिति को परिभाषित करने से:

1 = not processed 
2 = in progress 
3 = complete 

प्रत्येक कार्यकर्ता तो प्रसंस्कृत = 1 के साथ अगली पंक्ति मिलेगा, अपडेट 2 के लिए तो प्रसंस्कृत काम शुरू करो जब पूरा में काम अद्यतन किया जाता है प्रसंस्कृत 3. करने के लिए यह दृष्टिकोण भी अन्य प्रसंस्कृत परिणामों के विस्तार के लिए अनुमति होगी, उदाहरण के लिए के बजाय परिभाषित करने कि एक कार्यकर्ता complet है आप 'पूर्ण सफलतापूर्वक' और

'त्रुटियों के साथ पूर्ण' के लिए नई स्थितियां जोड़ सकते हैं
+0

धन्यवाद। कृपया मेरा संपादन देखें। क्या मैं आपके सुझाव के बारे में गलत हूं? – Synesso

+0

आप सही हैं, आपको अन्य लेन-देन को अद्यतन देखने की अनुमति देने के लिए अलग-अलग लेन-देन की आवश्यकता होगी, जो डिफ़ॉल्ट व्यवहार होना चाहिए - कार्यकर्ता प्रक्रिया को संसाधित करते समय आप लेनदेन को क्यों खोलेंगे? मैं समानता देख सकता हूं कि एक कार्यकर्ता स्वयं अनिवार्य रूप से एक लेनदेन है लेकिन एसक्यूएल सर्वर लेनदेन – Macros

0

शायद बेहतर विकल्प एक संस्करण/टाइमस्टैम्प कॉलम के साथ एक trisSate संसाधित कॉलम का उपयोग करेगा। संसाधित कॉलम में तीन मान तब इंगित करेंगे कि पंक्ति प्रसंस्करण, संसाधित या अनप्रचारित है या नहीं।

उदाहरण

CREATE TABLE Queue ID INT NOT NULL PRIMARY KEY, 
    Command NVARCHAR(100), 
    Processed INT NOT NULL CHECK (Processed in (0,1,2)), 
    Version timestamp) 

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

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

+0

धन्यवाद का उपयोग करने से यह लगभग निश्चित रूप से बेहतर कोडित है। कृपया मेरा संपादन देखें। साथ ही, निरंतर उपलब्धता के लिए, मैं चाहता हूं कि कोई भी उपलब्ध ग्राहक एक असफल नौकरी फिर से शुरू करे - न केवल वह जो विफल रहा। – Synesso

0

मैं किसी तालिका में ताले के साथ खिलवाड़ से दूर रहना होगा। बस दो अतिरिक्त कॉलम बनाएं जैसे IsProcessing (बिट/बूलियन) और प्रोसेसिंग स्टार्ट (डेटाटाइम)। जब कोई कर्मचारी समय-समय पर अपनी पंक्ति को क्रैश या अपडेट नहीं करता है तो आप डेटा को संसाधित करने का प्रयास कर सकते हैं।

+0

धन्यवाद। कृपया मेरा संपादन देखें। क्या इस समाधान को प्रारंभिक अद्यतन को मुख्य लेनदेन के बाहर होने की आवश्यकता है? – Synesso

+0

आप लेनदेन का उपयोग क्यों करना चाहते हैं? – ZippyV

0

एक तरीका एक अद्यतन अद्यतन कथन के साथ पंक्ति को चिह्नित करना है।यदि आप where खंड में स्थिति पढ़ते हैं और इसे set खंड में बदलते हैं, तो कोई अन्य प्रक्रिया बीच में नहीं आ सकती है, क्योंकि पंक्ति लॉक हो जाएगी। उदाहरण के लिए:

declare @pickup_id int 
set @pickup_id = 1 

set rowcount 1 

update YourTable 
set  status = 'picked up' 
,  @pickup_id = id 
where status = 'new' 

set rowcount 0 

return @pickup_id 

यह rowcount का उपयोग करता है अधिक से अधिक एक पंक्ति को अद्यतन करने के। यदि कोई पंक्ति नहीं मिली, @pickup_id-1 होगा।

8

मेरा जवाब यहाँ आप कतारों के रूप में तालिकाओं का उपयोग करने के लिए कैसे पता चलता है ... SQL Server Process Queue Race Condition

आप मूल रूप से की जरूरत है "चप्पू-आंकड़ा, READPAST, UPDLOCK" संकेत

+0

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

+0

@Andomar के साथ कतार पॉप करते हैं तो उन्हें आवश्यक या उपयोगी नहीं है: यह आवश्यक है: पाठकों और लेखकों के लिए 100% सुरक्षित सहमति ... – gbn

1

यदि आप एकाधिक ग्राहकों के लिए अपने परिचालनों को क्रमबद्ध करना चाहते हैं, तो आप बस एप्लिकेशन लॉक का उपयोग कर सकते हैं।

BEGIN TRANSACTION 

EXEC sp_getapplock @resource = 'app_token', @lockMode = 'Exclusive' 

-- perform operation 

EXEC sp_releaseapplock @resource = 'app_token' 

COMMIT TRANSACTION 
संबंधित मुद्दे