2010-09-03 13 views
6

मुझे एक एमएसएसक्ल डेटाबेस तालिका और समानांतर में एक ही तालिका तक पहुंचने वाली एक और 8 (समान) प्रक्रियाओं की आवश्यकता है - एक चयन शीर्ष एन बनाना, उन पंक्तियों को संसाधित करना, और अद्यतन करना उन पंक्तियों का स्तंभ। समस्या यह है कि मुझे केवल एक बार प्रत्येक पंक्ति का चयन और प्रक्रिया करने की आवश्यकता है। इसका मतलब यह है कि यदि एक प्रक्रिया डेटाबेस में पहुंच गई और शीर्ष एन पंक्तियों का चयन किया गया, तो दूसरी प्रक्रिया आने पर उन्हें उन पंक्तियों को बंद कर दिया जाना चाहिए और पंक्तियों को एन से 2 * एन पंक्तियों का चयन करना चाहिए, और इसी तरह ..."चयन शीर्ष एन" क्वेरी में अनलॉक पंक्तियों को वापस लौटें

क्या आप उन्हें चुनते समय कुछ पंक्तियों पर लॉक रखना संभव है, और जब कोई शीर्ष पंक्तियों को अनुरोध करता है जो अगली पंक्तियों को वापस करने के लिए बंद कर दिए जाते हैं, और लॉक वाले लोगों की प्रतीक्षा नहीं करते हैं? एक लंबे शॉट की तरह लगता है, लेकिन ...

एक और चीज जो मैं सोच रहा था - शायद इतना सुरुचिपूर्ण नहीं है लेकिन सरल और सुरक्षित लगता है, डेटाबेस में उस तालिका में चयन किए गए उदाहरणों के लिए काउंटर होना है। पहला उदाहरण जो काउंटर बढ़ाता है और शीर्ष एन का चयन करेगा, अगला वाला काउंटर बढ़ाएगा और एन * (i-1) से n * i तक पंक्तियों का चयन करेगा, और इसी तरह ...

क्या यह ध्वनि एक अच्छी ideea की तरह? क्या आपके पास कोई बेहतर सुझाव है? किसी भी विचार की अत्यधिक सराहना की है!

आपके समय के लिए धन्यवाद।

+3

ऐसा लगता है जैसे आप एक कतार के रूप में एक टेबल का उपयोग कर रहे हैं? आपको [यह आलेख] मिल सकता है (http: // rusanu।कॉम/2010/03/26/उपयोग-टेबल-ए-कतार /) [रीमस Rusanu] द्वारा (http://stackoverflow.com/users/105929/remus-rusanu) उपयोगी। –

+0

लिंक के लिए धन्यवाद। इसके बारे में जानना दिलचस्प था, लेकिन जब से मैं उन्हें चुनने के बाद पंक्तियों को रखने की जरूरत है (उन्हें हटाने का विकल्प नहीं है), यह मेरे मामले में वास्तव में सहायक नहीं है। – Diana

+1

आपके पास 'संसाधित' बिट कॉलम हो सकता है और संभवतः 'DELETE' के लिए 'अद्यतन' को प्रतिस्थापित कर सकता है। यदि आप काउंटर समाधान का उपयोग करने का निर्णय लेते हैं [यह उत्तर] (http://stackoverflow.com/questions/3453411/sql-server-auto-incrementation-that-allows-update-statements/3462957#3462957) मदद कर सकता है। –

उत्तर

6

यहां नमूने I blogged about a while ago है:

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

DECLARE @NextId INTEGER 
BEGIN TRANSACTION 

-- Find next available item available 
SELECT TOP 1 @NextId = ID 
FROM QueueTable WITH (UPDLOCK, READPAST) 
WHERE IsBeingProcessed = 0 
ORDER BY ID ASC 

-- If found, flag it to prevent being picked up again 
IF (@NextId IS NOT NULL) 
    BEGIN 
     UPDATE QueueTable 
     SET IsBeingProcessed = 1 
     WHERE ID = @NextId 
    END 

COMMIT TRANSACTION 

-- Now return the queue item, if we have one 
IF (@NextId IS NOT NULL) 
    SELECT * FROM QueueTable WHERE ID = @NextId 
+0

आपके उत्तरदाता के लिए धन्यवाद, READPAST MsSQL उत्तर की तरह लगता है मैं देख रहा था। यदि वह SELECT TOP 1 @NextId = ID लाखों रिकॉर्डों की कई तालिकाओं पर एक चुनिंदा शीर्ष 3000 है, तो इसमें कुछ समय लग सकता है। क्या यह रीडपैस्ट द्वारा "गारंटीकृत" है कि यदि मेरे पास एक और धागा सटीक समान चयन कर रहा है, तो दूसरा अगला अनब्लॉक वाली पंक्तियां उठाएगा? – Diana

+0

मैंने एक साधारण परीक्षण तालिका पर आपके दृष्टिकोण का परीक्षण किया, एक आकर्षण के रूप में काम करता है। लेकिन मेरी वास्तविक तालिका (बहुत बड़ी, इंडेक्स और इसके आंकड़े) पर, यह केवल कभी-कभी काम करता है ... अन्य बार, लॉक वाली पंक्तियों को नहीं छोड़ता है, यह पंक्तियों खत्म होने के पिछले चयन लॉक होने तक बस "लटकता है" (इसका परीक्षण करने के लिए मैंने "एटोर देरी '00: 00: 10 '" जोड़ा)। कोई विचारधारा क्यों हो रहा है? – Diana

+0

@ डायना - आप प्रति प्रक्रिया को लॉक करने की कितनी पंक्तियां कोशिश कर रहे हैं? जैसे शायद एक टेबल लॉक लिया जा रहा है (पंक्तियों को एक निश्चित दहलीज पर टेबल ताले में अपग्रेड कर दिया जाएगा)। यदि आप एक उदाहरण स्क्रिप्ट पोस्ट कर सकते हैं जो दर्शाता है कि आप इसे कैसे कर रहे हैं (ओबीवी के रूप में। मेरा उदाहरण केवल एक रिकॉर्ड के लिए था), यह बहुत अच्छा होगा - अधिकतम एक्सपोजर – AdaTheDev

2

सबसे सरल विधि row locking उपयोग करने के लिए है:

BEGIN TRAN 

SELECT * 
FROM authors 
WITH (HOLDLOCK, ROWLOCK) 
WHERE au_id = '274-80-9391' 

/* Do all your stuff here while the record is locked */ 

COMMIT TRAN 

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

आपको पंक्तियों को लॉक करने की कितनी देर आवश्यकता होगी? आपके द्वारा चुने गए पंक्तियों पर काउंटर लगाने के लिए वास्तव में सबसे अच्छा तरीका हो सकता है (के भीतर OUTPUT क्लॉज का उपयोग करके सबसे अच्छा किया गया है)।

+0

मुझे चयन के बाद कनेक्शन बंद करने की आवश्यकता है, और पंक्तियों के बैच को प्रोसेस करने में कुछ समय लगेगा (प्रत्येक पंक्ति 500kb लगाव के साथ एक ई-मेल भेजने का निर्धारण करेगी)। – Diana

+0

मैं कहूंगा कि आपको पंक्तियों को लॉक करने की अपनी विधि को लागू करने की आवश्यकता है (जैसे काउंटर) क्योंकि पंक्ति लॉकिंग लंबे समय तक अनुरोधों को अवरुद्ध कर सकती है कि आपके पास टाइमआउट त्रुटियां कहीं और दिखाई देगी। मार्टिन की टिप्पणी आगे बढ़ने की तरह दिखती है http://stackoverflow.com/questions/3636950/return-unlocked-rows-in-a-select-top-n-query#comment-3822218 – Codesleuth

0

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

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

यदि आपको टेबल और प्रक्रियाओं को लिखने के लिए हाथ की आवश्यकता है जो ऐसा करेंगे (बस और सुरक्षित रूप से इसे रखकर!) बस पूछें।

+0

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

0

संपादित करें: आह, कभी नहीं, आप एक डिस्कनेक्ट शैली में काम कर रहे हैं। कैसे इस बारे में:

UPDATE TOP (@n) QueueTable SET Locked = 1 
OUTPUT INSERTED.Col1, INSERTED.Col2 INTO @this 
WHERE Locked = 0 

<do your stuff> 

शायद आप READPAST संकेत के लिए देख रहे हैं?

<begin or save transaction> 

INSERT INTO @this (Col1, Col2) 
SELECT TOP (@n) Col1, Col2 
FROM Table1 WITH (ROWLOCK, HOLDLOCK, READPAST) 

<do your stuff> 

<commit or rollback> 
संबंधित मुद्दे