मैं एक समय में एक व्यक्ति द्वारा चलाई जाने वाली SQL संग्रहित प्रक्रिया को कैसे सीमित करूं?


12

मेरे पास एक संग्रहीत प्रक्रिया है जो मूल रूप से एक तालिका से मूल्यों का चयन करती है और उन्हें दूसरे में सम्मिलित करती है, एक प्रकार का संग्रह। मैं एक ही समय में कई लोगों को ऐसा करने से बचना चाहता हूं।

जब यह प्रक्रिया चल रही है, मैं नहीं चाहता कि कोई और इसे शुरू करने में सक्षम हो, हालांकि मैं क्रमबद्धता नहीं चाहता, दूसरा व्यक्ति प्रक्रिया को चलाने के बाद मैं इसके साथ काम कर रहा हूं।

मैं जो चाहता हूं, वह त्रुटि प्राप्त करने के लिए इसे शुरू करने की कोशिश कर रहे दूसरे व्यक्ति के लिए है, जबकि मैं प्रक्रिया चला रहा हूं।

मैंने sp_getapplock का उपयोग करने की कोशिश की है, हालांकि मैं प्रक्रिया को चलाने से व्यक्ति को पूरी तरह से रोकने का प्रबंधन नहीं कर सकता।

मैंने sysinos_exec_requests के साथ प्रक्रिया खोजने और प्रक्रिया को अवरुद्ध करने की भी कोशिश की, जबकि यह काम करता है, मुझे लगता है कि यह इष्टतम नहीं है क्योंकि कुछ सर्वरों पर मुझे sysinos_exec_sql_text (sql_handle) चलाने की अनुमति नहीं है।

मेरे लिए ऐसा करने का सबसे अच्छा तरीका क्या है?


3
क्या आप एक कदम पीछे ले जा सकते हैं, और प्रक्रिया क्या कर रही है, इसके बारे में कुछ और जानकारी प्रदान करें, और आप एक ही समय में कई लोगों को इसे चलाने से क्यों बचना चाहते हैं? एक कोडिंग तकनीक हो सकती है जो इस आवश्यकता को समाप्त करती है, या कुछ प्रकार की कतारें जो आप चीजों को संभालने के लिए लागू कर सकते हैं।
AMtwo

जवाबों:


15

@ टिबोर-कारज़ी के जवाब में जोड़ने के लिए, लॉक टाइमआउट सेट करने से वास्तव में कोई त्रुटि उत्पन्न नहीं होती (मैंने डॉक्स के खिलाफ पीआर सबमिट किया है)। sp_getapplock सिर्फ रिटर्न -1 देता है, इसलिए आपको रिटर्न वैल्यू चेक करनी होगी। तो इस तरह से:

create or alter procedure there_can_be_only_one 
as
begin
begin transaction

  declare @rv int
  exec @rv = sp_getapplock 'only_one','exclusive','Transaction',0
  if @rv < 0
   begin
      throw 50001, 'There is already an instance of this procedure running.', 10
   end

  --do stuff
  waitfor delay '00:00:20'


commit transaction
end

8

खरीद की शुरुआत में sp_getapplock का उपयोग करें, और बहुत कम मूल्य पर लॉक टाइमआउट सेट करें। इस तरह से आपको ब्लॉक होने पर एक त्रुटि मिलती है।


7

एक अन्य विकल्प प्रक्रिया तक पहुंच को नियंत्रित करने के लिए एक तालिका का निर्माण करना है। नीचे दिया गया उदाहरण एक संभावित तालिका के साथ-साथ एक ऐसी प्रक्रिया को दिखाता है जो इसका उपयोग कर सकती है।

CREATE TABLE dbo.ProcedureLock
    (
    ProcedureLockID INT NOT NULL IDENTITY(1,1)
    , ProcedureName SYSNAME NOT NULL
    , IsLocked BIT NOT NULL CONSTRAINT DF_ProcedureLock_IsLocked DEFAULT (0)
    , UserSPID INT NULL
    , DateLockTaken DATETIME2(7) NULL
    , DateLockExpires DATETIME2(7) NULL
    , CONSTRAINT PK_ProcedureLock PRIMARY KEY CLUSTERED (ProcedureLockID)
    )

CREATE UNIQUE NONCLUSTERED INDEX IDXUQ_ProcedureLock_ProcedureName
    ON dbo.ProcedureLock (ProcedureName)

INSERT INTO dbo.ProcedureLock
    (ProcedureName, IsLocked)
VALUES ('dbo.DoSomeWork', 0)

GO

CREATE PROCEDURE dbo.DoSomeWork
AS
BEGIN

    /** Take Lock */
    UPDATE dbo.ProcedureLock
    SET IsLocked = 1
        , UserSPID = @@SPID
        , DateLockTaken = SYSDATETIME()
        , DateLockExpires = DATEADD(MINUTE, 10, SYSDATETIME())
    WHERE ProcedureName = 'dbo.DoSomeWork'
        AND (IsLocked = 0
            OR (IsLocked = 1 AND DateLockExpires < SYSDATETIME())
            )

    IF COALESCE(@@ROWCOUNT, 0) = 0
    BEGIN
        ;THROW 50000, 'This procedure can only be run one at a time, please wait', 1;
    END

    /** DO WHATEVER NEEDS TO BE DONE */

    /** Release the lock */
    UPDATE dbo.ProcedureLock
    SET IsLocked = 0
        , UserSPID = NULL
        , DateLockTaken = NULL
        , DateLockExpires = NULL
    WHERE ProcedureName = 'dbo.DoSomeWork'

END

1
यह बहुत ही समान है (या शायद उसी के समान) जो मैंने प्रश्न को पढ़ने के तुरंत बाद सोचा था, लेकिन मेरे पास इस विचार के साथ एक मुद्दा था कि मुझे पूरी तरह से यकीन नहीं था कि इसे कैसे संबोधित किया जाए और इसे आपके उत्तर में संबोधित नहीं किया जा सकता है। या तो। मेरी चिंता यह है कि क्या होगा अगर "जो कुछ भी करने की आवश्यकता है" भाग के दौरान कुछ होता है? आप उस IsLockedस्थिति में राज्य को 0 पर कैसे रीसेट करेंगे ? मैं COALESCEयहाँ आपके उपयोग के बारे में भी उत्सुक हूँ । कर सकते हैं @@ROWCOUNTअशक्त हो बयानों की तरह के बाद UPDATE? अंत में, सिर्फ एक छोटी सी नाइटपिक, THROWउस विशिष्ट मामले में बयान के सामने एक अर्धविराम क्यों रखा ?
एंड्री एम

ताला समाप्ति का एक तरीका है कि हैंडलिंग। इसे एक उचित समय सीमा पर सेट करने की आवश्यकता होगी, मैंने इसे अपने उदाहरण में 10 मिनट के लिए सेट किया है। आप एक कोशिश / कैच ब्लॉक में अपने काम के तर्क को अतिक्रमण कर सकते हैं और यदि आप चाहते हैं तो कैच में अनलॉक कर सकते हैं। मैं आदत से बाहर का उपयोग करता हूं, लेकिन कोई भी @@ रोवल नहीं हो सकता है। अग्रणी अर्ध-बृहदान्त्र विजुअल स्टूडियो डेटाबेस प्रोजेक्ट्स के साथ काम करने से आता है, यह शिकायत करता है कि यह वहाँ नहीं है। कोई नुकसान नहीं है।
जोनाथन फाइट

-1

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

विभिन्न प्रकार की डेटाबेस विसंगतियों से बचाने के लिए, SQL मानक में चार ट्रांजेक्शन आइसोलेशन स्तर होते हैं:

  • READ UNCOMMITTED जहां मूल रूप से लेनदेन अपना मूल्य खो देते हैं, अन्य लेनदेन गंदे डेटा को देखते हैं। यह प्रयोग न करें!
  • पढ़ें जहां लेनदेन केवल प्रतिबद्ध डेटा देखते हैं, लेकिन ऐसी विसंगतियां हो सकती हैं जहां दो लेनदेन एक दूसरे के पैर की उंगलियों पर कदम रख सकते हैं
  • दोहराई गई प्रतिक्रिया जहां एक प्रकार की असंगतता, गैर-दोहराई जाने वाली रीड, को हल किया जाता है
  • अनुक्रमिक जो गारंटी देता है कि कुछ आभासी आदेश मौजूद है जिसमें लेनदेन को निष्पादित करने से उन परिणामों को प्राप्त होगा जो उनके निष्पादन के परिणामस्वरूप हुए थे

हालाँकि, SQL मानक में इन डेटाबेस विसंगतियों के लिए एक लॉकिंग आधारित दृष्टिकोण है, और प्रदर्शन कारणों से कई डेटाबेस स्नैपशॉट अलगाव आधारित दृष्टिकोण लेते हैं जो मूल रूप से इन स्तरों पर हैं:

  • READ COMMITTED जो लॉकिंग डेटाबेस में है वही है
  • SNAPSHOT अलगाव जहां डेटाबेस सभी डेटा का एक स्नैपशॉट देखता है और अगर यह किसी अन्य लेन-देन द्वारा अपडेट की गई पंक्ति को अपडेट करने का प्रयास करता है, तो इसे रद्द कर दिया जाता है, फिर भी कुछ प्रसिद्ध विसंगतियां हैं जो हो सकती हैं
  • अनुक्रमिक जो कि वैसा ही है जैसा कि लॉकिंग डेटाबेस में है, लेकिन इस बार एक अलग तरीके से कार्यान्वित किया जाता है, ताले लेने से नहीं, लेकिन यह सुनिश्चित करने से कि कोई धारावाहिक उल्लंघन नहीं होता है, और यदि ऐसा उल्लंघन पाया जाता है, तो लेनदेन रद्द करना

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

आप जो चाहते हैं वह SERIALIZABLE अलगाव स्तर है: यह सुनिश्चित करता है कि यदि लेनदेन एक अच्छे राज्य में दूसरे परिणाम के बाद स्वतंत्र रूप से निष्पादित किया जाता है, तो लेन-देन के किसी भी समानांतर निष्पादन के परिणामस्वरूप भी एक अच्छी स्थिति होती है। सौभाग्य से, माइकल काहिल है उनकी डॉक्टरेट शोध प्रबंध में पता चला कैसे serializable अलगाव स्तर कम प्रयास के साथ स्नैपशॉट पृथक डेटाबेस द्वारा समर्थित किया जा सकता है।

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

अब, SQL सर्वर वास्तव में SERIALIZABLE आइसोलेशन स्तर का समर्थन करता है (बदले में SER कीवर्ड के पीछे स्नैपशॉट अलगाव के बजाय )? स्पष्ट रूप से, मुझे नहीं पता: एकमात्र डेटाबेस जो मुझे पता है कि यह समर्थन करता है वह PostgreSQL है।

भले ही मैं SQL सर्वर को विशिष्ट सलाह देने में विफल रहा, फिर भी मैं अभी भी इस उत्तर को पोस्ट कर रहा हूं, क्योंकि PostgreSQL के उपयोगकर्ता और अन्य डेटाबेस के उपयोगकर्ता जो PostgreSQL पर स्विच करने पर विचार कर सकते हैं, वे मेरे उत्तर से लाभ उठा सकते हैं। इसके अलावा, गैर- PostgreSQL डेटाबेस के उपयोगकर्ता जो PostgreSQL पर स्विच नहीं कर सकते हैं, वे अपने पसंदीदा डेटाबेस विक्रेता पर वास्तविक SERIALIZABLE अलगाव स्तर की पेशकश कर सकते हैं ।


मुझे लगता है कि यह डाउनवोट का मतलब है कि किसी ने जांच की कि क्या SQL सर्वर में SERIALIZABLE अलगाव स्तर है और पता चला कि यह नहीं है।
जूही

-2

मुझे एहसास है कि 'वास्तविक' समस्या अधिक जटिल हो सकती है।

यदि ऐसा नहीं है: यदि आप अपनी प्रविष्टि के साथ अपनी प्रविष्टि करते हैं और / या अपडेट ट्रिगर करते हैं तो आप उस समस्या से बच सकते हैं जिसे आप हल करने का प्रयास कर रहे हैं।

आशा है कि मदद करता है,
-क्रिस सी।


1
"तुरंत" से आपका क्या मतलब है? इसके तुरंत बाद क्या? डालने के बाद? इसलिए जैसे ही कोई नई पंक्ति आती है, उसे तुरंत आर्काइव में भेज दिया जाता है? या अपडेट के बाद आपका क्या मतलब था? तो कोई भी डेटा परिवर्तन संग्रह को ट्रिगर करता है? शायद आपको इस बारे में अधिक विशिष्ट होना चाहिए कि आपके पास यह सुझाव देने का कौन सा परिदृश्य है।
एंड्री एम

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

@underscore_d हाँ, यह बहुत महंगा हो सकता है या हमेशा आवश्यक नहीं होता है। यही कारण है कि मैंने अपना उत्तर उस कथन के साथ शुरू किया है the 'real' problem may be more complex। इस घटना में कि यह नहीं है, ट्रिगर एक अच्छा समाधान है। साथ ही यह शायद परीक्षण करना और बनाए रखना आसान होगा क्योंकि यह कस्टम समाधान की बजाय डेटाबेस की एक विशेषता है।
जे। क्रिस कॉम्पटन

@AndriyM मैंने ट्रिगर को सम्मिलित / अद्यतन करने के लिए रेफ के साथ, तुरंत शब्द हटा दिया। गलतफहमी के लिए खेद है।
जे। क्रिस कॉम्पटन

1
मैंने प्रश्न को फिर से पढ़ा है और मुझे लगता है कि मैं अपने भ्रम का स्रोत देख सकता हूं। यहां आप जो सुझाव दे रहे हैं, वह संग्रह करने की तुलना में ऑडिट करने के लिए अधिक महत्वपूर्ण है। जैसा कि मैं समझता हूं, संग्रह डेटा का अर्थ है डेटा को स्थानांतरित करना (जैसे एक तालिका से दूसरी तालिका)। हालांकि, भले ही ओपी ने अपनी प्रक्रिया के फ़ंक्शन को "एक प्रकार का संग्रह" के रूप में संक्षेपित किया, उन्होंने कभी यह नहीं कहा कि डेटा स्रोत से हटा दिया जाएगा, केवल यह कि इसे इसमें से चुना जाएगा और लक्ष्य में डाला जाएगा। तो मैं आपको अनुमान लगा रहा हूं कि ओपी को स्थानांतरित करने के बजाय कॉपी करने की जरूरत है , उनका डेटा, जिस स्थिति में ट्रिगर्स का उपयोग करना संभवतः समझ में आता है।
एंड्री एम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.