ताला वृद्धि - यहाँ क्या हो रहा है?


138

SQL Server 2008 में एक तालिका (किसी स्तंभ को हटाते हुए) को परिवर्तित करते समय, मैंने जेनरेट चेंज स्क्रिप्ट बटन पर क्लिक किया और मैंने देखा कि यह जो परिवर्तन स्क्रिप्ट उत्पन्न हुई है वह स्तंभ को गिरा देती है, "गो" कहती है और फिर सेट होने के लिए प्रकट होने वाला एक अतिरिक्त परिवर्तन कथन चलाता है। "टेबल" के लिए तालिका के लिए ताला वृद्धि। उदाहरण:

ALTER TABLE dbo.Contract SET (LOCK_ESCALATION = TABLE)

मुझे यह भी ध्यान देना चाहिए कि यह आखिरी चीज है जो परिवर्तन स्क्रिप्ट कर रही है। यह यहां क्या कर रहा है और यह LOCK_ESCALATION को TABLE में क्यों सेट कर रहा है?

जवाबों:


165

" लॉक एस्केलेशन " कैसे SQL बड़े अपडेट के लिए लॉकिंग को हैंडल करता है। जब एसक्यूएल बहुत सी पंक्तियों को बदलने जा रहा है, तो डेटाबेस इंजन के लिए कई छोटी चीज़ों (जैसे पंक्ति ताले) को लॉक करने के बजाय कम, बड़े ताले (जैसे पूरी तालिका) लेना अधिक कुशल है।

लेकिन जब आपके पास एक विशाल तालिका हो तो यह समस्याग्रस्त हो सकता है, क्योंकि संपूर्ण तालिका पर ताला लगाने से लंबे समय तक अन्य क्वेरीज़ लॉक हो सकती हैं। यह ट्रेडऑफ़ है: कई छोटे-दाने वाले ताले कम (या एक) मोटे अनाज वाले ताले से धीमी होते हैं, और एक टेबल के विभिन्न हिस्सों को लॉक करने वाले कई प्रश्न होने पर गतिरोध की संभावना बन जाती है यदि एक प्रक्रिया दूसरे पर प्रतीक्षा कर रही हो।

LOCK_ESCALATIONएसक्यूएल 2008 में नया एक टेबल-स्तरीय विकल्प है , जो लॉक एस्केलेशन को नियंत्रित करने की अनुमति देता है। डिफ़ॉल्ट, "टेबल" ताले को सभी तरह से टेबल स्तर तक बढ़ाने की अनुमति देता है। असमर्थ ज्यादातर मामलों में पूरी मेज पर ताला वृद्धि को रोकता है। AUTO टेबल को लॉक करने की अनुमति देता है, सिवाय इसके कि टेबल का विभाजन किया गया है, जिस स्थिति में लॉक केवल विभाजन स्तर तक बने हैं। अधिक जानकारी के लिए इस ब्लॉग पोस्ट को देखें ।

मुझे संदेह है कि IDE इस सेटिंग को तब बनाता है जब तालिका को फिर से बनाया जाता है क्योंकि TABLE SQL 2008 में डिफ़ॉल्ट है। ध्यान दें कि LOCK_ESCALATION SQL 2005 में समर्थित नहीं है, इसलिए आपको स्क्रिप्ट को चलाने की कोशिश करने पर इसे हटाने की आवश्यकता होगी 2005 का उदाहरण। इसके अलावा, चूंकि TABLE डिफ़ॉल्ट है, आप अपनी स्क्रिप्ट को फिर से चलाते समय उस लाइन को सुरक्षित रूप से हटा सकते हैं।

यह भी ध्यान दें कि, SQL 2005 में इस सेटिंग के मौजूद होने से पहले, सभी लॉक टेबल स्तर तक बढ़ सकते हैं - दूसरे शब्दों में, "TABLE" SQL 2005 पर एकमात्र सेटिंग थी।


1
MSDN फ़ोरम पर डुप्लीकेट पोस्ट के साथ ही: social.msdn.microsoft.com/Forums/en-US/sqldatabaseengine/thread/…
जोनाथन केहियास

6
@dma_k - यह विकल्प प्रासंगिक नहीं है CREATE TABLEक्योंकि तालिका अभी तक मौजूद नहीं है इसलिए लॉक करने के लिए कुछ भी नहीं है।
जस्टिन ग्रांट

1
लेकिन SSMS में तालिका डिज़ाइन करते समय परिवर्तन स्क्रिप्ट में प्रारंभिक ALABLE तालिका कथन के बाद LOCK_ESCALATION कथन क्यों है ? निश्चित रूप से उस समय तक काम पहले ही हो चुका है। क्या यह तालिका की संरचना को बदलने से पहले नहीं होना चाहिए ?
उल्टा इंजीनियर

2
@DaveBoltman - SET ALTER TABLE स्टेटमेंट का हिस्सा है। यह एक अलग बयान नहीं है। देखें docs.microsoft.com/en-us/sql/t-sql/statements/...
जस्टिन अनुदान

2
जस्टिनग्रांट, अभी भी, @DaveBoltman से सवाल खड़ा है। SSMS के लिए जो स्क्रिप्ट उत्पन्न होती है, कहते हैं, एक नए कॉलम को जोड़ने के दो अलग-अलग ALTER TABLEकथन हैं। पहले ALTER TABLE ADD column, फिर GO, फिर दूसरा ALTER TABLE SET LOCK_ESCALATION=TABLE, फिर दूसरा GO। तो, LOCK_ESCALATIONस्तंभ जोड़ने के बाद सेट किया गया है। तथ्य के बाद इसे स्थापित करने की क्या बात है? ये दो ALTER TABLEकथन एक लेनदेन में लिपटे हुए हैं, लेकिन फिर भी कॉलम LOCK_ESCALATIONको सेट होने से पहले जोड़ा जाता है। मुझे लगता है कि मैं थोड़ा और खुदाई करूंगा और दूसरा जवाब लिखूंगा।
व्लादिमीर बारानोव

11

यदि आप अपनी स्क्रिप्ट के मुख्य भाग को चलाने से पहले और बाद में इस मान की तुलना करके अपनी स्क्रिप्ट में LOCK_ESCALATION कथन शामिल करना चाहते हैं, तो आप यह देख सकते हैं:

SELECT lock_escalation_desc FROM sys.tables WHERE name='yourtablename'

मेरे मामले में, एक मान को छोड़ने या जोड़ने के लिए तालिका में परिवर्तन करने से यह मान संशोधित नहीं होता है।


11

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

मैंने कुछ परीक्षण किए और यहां जो कुछ हो रहा है, उसकी मेरी समझ है।

लघु संस्करण

ALTER TABLEएक कॉलम में जुड़ने वाले कॉलम को जोड़ने, छोड़ने या बदलने का विवरण तालिका में एक स्कीमा संशोधित (SCH-M) लॉक लेता है, जिसका तालिका की LOCK_ESCALATIONसेटिंग से कोई लेना-देना नहीं है । LOCK_ESCALATIONDML बयान (दौरान व्यवहार ताला को प्रभावित करता है INSERT, UPDATE, DELETE, आदि), DDL बयान के दौरान नहीं ( ALTER)। SCH-M लॉक हमेशा इस उदाहरण में पूरे डेटाबेस ऑब्जेक्ट का टेबल होता है।

यह संभावना है कि भ्रम कहां से आता है।

SSMS ALTER TABLE <TableName> SET (LOCK_ESCALATION = ...)अपने स्क्रिप्ट को सभी मामलों में जोड़ता है , तब भी जब इसकी आवश्यकता नहीं है। ऐसे मामलों में जब इस कथन की आवश्यकता होती है, इसे तालिका की वर्तमान सेटिंग को संरक्षित करने के लिए जोड़ा जाता है, कि उस स्क्रिप्ट में होने वाले टेबल स्कीमा में परिवर्तन के दौरान तालिका को कुछ विशिष्ट तरीके से लॉक करने के लिए ।

दूसरे शब्दों में, तालिका को पहले ALTER TABLE ALTER COLUMNस्टेटमेंट पर SCH-M लॉक के साथ लॉक किया गया है, जबकि टेबल स्कीमा को बदलने का सारा काम किया गया है। अंतिम ALTER TABLE SET LOCK_ESCALATIONकथन इसे प्रभावित नहीं करता है। यह केवल भविष्य DML बयान (को प्रभावित करता है INSERT, UPDATE, DELETE, आदि) कि तालिका के लिए।

पहली नज़र में ऐसा लगता SET LOCK_ESCALATION = TABLEहै कि इस तथ्य से कोई लेना-देना नहीं है कि हम पूरी तालिका बदल रहे हैं (हम यहां अपना स्कीमा बदल रहे हैं), लेकिन यह भ्रामक है।

दीर्घ संस्करण

जब कुछ मामलों में तालिका में फेरबदल किया जाता है तो SSMS एक स्क्रिप्ट उत्पन्न करता है जो पूरी तालिका को पुन: बनाता है और कुछ सरल मामलों में (जैसे किसी स्तंभ को जोड़ना या छोड़ना) स्क्रिप्ट तालिका को फिर से नहीं बनाती है।

आइए इस नमूना तालिका को एक उदाहरण के रूप में लेते हैं:

CREATE TABLE [dbo].[Test](
    [ID] [int] NOT NULL,
    [Col1] [nvarchar](50) NOT NULL,
    [Col2] [int] NOT NULL,
 CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

प्रत्येक तालिका में एक LOCK_ESCALATIONसेटिंग है, जो TABLEडिफ़ॉल्ट रूप से सेट है । आइए इसे यहां बदलें:

ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)

अब, यदि मैं Col1SSMS टेबल डिज़ाइनर में टाइप बदलने की कोशिश करता हूँ , SSMS एक स्क्रिप्ट बनाता है जो पूरी टेबल को फिर से बनाता है:

BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Tmp_Test
    (
    ID int NOT NULL,
    Col1 nvarchar(10) NOT NULL,
    Col2 int NOT NULL
    )  ON [PRIMARY]
GO
ALTER TABLE dbo.Tmp_Test SET (LOCK_ESCALATION = DISABLE)
GO
IF EXISTS(SELECT * FROM dbo.Test)
     EXEC('INSERT INTO dbo.Tmp_Test (ID, Col1, Col2)
        SELECT ID, CONVERT(nvarchar(10), Col1), Col2 FROM dbo.Test WITH (HOLDLOCK TABLOCKX)')
GO
DROP TABLE dbo.Test
GO
EXECUTE sp_rename N'dbo.Tmp_Test', N'Test', 'OBJECT' 
GO
ALTER TABLE dbo.Test ADD CONSTRAINT
    PK_Test PRIMARY KEY CLUSTERED 
    (
    ID
    ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

GO
COMMIT

आप ऊपर देख सकते हैं कि यह LOCK_ESCALATIONनई बनाई गई तालिका के लिए सेट है । SSMS यह तालिका की वर्तमान सेटिंग को संरक्षित करने के लिए करता है। SSMS इस लाइन को उत्पन्न करता है, भले ही सेटिंग का वर्तमान मान डिफ़ॉल्ट TABLEमान हो। यदि मैं भविष्य में इस डिफ़ॉल्ट परिवर्तन को सुरक्षित और स्पष्ट और संभव भविष्य की समस्याओं को रोक सकता हूं, तो मुझे लगता है। यह समझ में आता है।

इस उदाहरण में SET LOCK_ESCALATIONकथन को उत्पन्न करना वास्तव में आवश्यक है , क्योंकि तालिका को नए सिरे से बनाया गया है और इसकी सेटिंग को संरक्षित किया जाना है।

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

BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE dbo.Test ADD
    NewCol nchar(10) NULL
GO
ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)
GO
COMMIT

जैसा कि आप देख सकते हैं, यह अभी भी ALTER TABLE SET LOCK_ESCALATIONबयान जोड़ता है , भले ही इस मामले में इसकी बिल्कुल भी आवश्यकता नहीं है। पहला ALTER TABLE ... ADDवर्तमान सेटिंग नहीं बदलता है। मुझे लगता है, एसएसएमएस डेवलपर्स ने फैसला किया कि यह निर्धारित करने के प्रयास के लायक नहीं है कि यह ALTER TABLE SET LOCK_ESCALATIONकथन किस मामले में बेमानी है और इसे हमेशा उत्पन्न करना है, बस सुरक्षित रहने के लिए। हर बार इस बयान को जोड़ने में कोई बुराई नहीं है।

एक बार फिर, तालिका-चौड़ी LOCK_ESCALATIONसेटिंग अप्रासंगिक है जबकि तालिका स्कीमा ALTER TABLEविवरण के माध्यम से बदल जाती है । LOCK_ESCALATIONसेटिंग केवल डीएमएल स्टेटमेंट्स के लॉकिंग व्यवहार को प्रभावित करती है, जैसे UPDATE

अंत में, एक उद्धरण ALTER TABLE, मेरा जोर:

ALTER TABLE में निर्दिष्ट परिवर्तन तुरंत लागू हो जाते हैं। यदि परिवर्तनों को तालिका में पंक्तियों के संशोधनों की आवश्यकता होती है, तो ALTER TABLE पंक्तियों को अपडेट करती है। अन्य तालिका में एक स्कीमा संशोधित (SCH-M) लॉक को सुनिश्चित करने के लिए सुनिश्चित करें कि परिवर्तन के दौरान तालिका के लिए कोई अन्य कनेक्शन संदर्भ मेटाडेटा भी नहीं है।, सिवाय ऑनलाइन इंडेक्स ऑपरेशंस के जिन्हें अंत में बहुत ही कम SCH-M लॉक की आवश्यकता होती है। ALTER TABLE ... SWITCH ऑपरेशन में, लॉक को स्रोत और लक्ष्य तालिकाओं दोनों पर अधिग्रहित किया जाता है। तालिका में किए गए संशोधन लॉग और पूरी तरह से पुनर्प्राप्त करने योग्य हैं। परिवर्तन जो बहुत बड़ी तालिकाओं में सभी पंक्तियों को प्रभावित करते हैं, जैसे कि एक कॉलम को ड्रॉप करना या SQL सर्वर के कुछ संस्करणों पर, डिफ़ॉल्ट मान के साथ एक नॉट NULL कॉलम को जोड़ने में, कई लॉग रिकॉर्ड्स को पूरा करने और उत्पन्न करने में लंबा समय लग सकता है। किसी भी INSERT, UPDATE, या DELETE कथन के रूप में इन सावधानियों के बयान को उसी देखभाल के साथ निष्पादित किया जाना चाहिए जो इन पंक्तियों को प्रभावित करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.