"क्वेरी सम्मिलित करें" से पहले "शुरुआती लेनदेन" क्यों पूरी मेज को बंद कर देता है?


11

मैं SQL Server 2005 एक्सप्रेस का उपयोग कर रहा हूं।

एक परिदृश्य में, मैंने एक संग्रहीत प्रक्रिया में एक बयान Begin Transactionसे ठीक पहले कमांड जोड़ा INSERT। जब मैंने इस संग्रहित प्रक्रिया को अंजाम दिया, तो इसने पूरी तालिका को बंद कर दिया और सभी समवर्ती कनेक्शनों ने इसे INSERTसमाप्त होने तक एक लटका हुआ प्रदर्शन दिखाया ।

संपूर्ण तालिका लॉक क्यों हो जाती है और मैं SQL सर्वर 2005 एक्सप्रेस में इस समस्या को कैसे दूर करूं?

संपादित

क्वेरी निम्नानुसार है:

INSERT INTO <table2> SELECT * FROM <table1> WHERE table1.workCompleted = 'NO'

2
यह तालिका को postgresql में बंद नहीं करता है।
स्कॉट मारलोए

और अधिक @RPK की आवश्यकता है। तालिका DDL और आवेषण के एक नमूने के साथ हम आपको व्हाट्सएप के सटीक विवरण दे सकते हैं। इसके बिना हम सिर्फ अनुमान लगा रहे हैं।
मार्क मंजिला-स्मिथ

यह प्रश्न बहुत अस्पष्ट है। मैं अन्य DBMS के किसी भी संदर्भ को हटा रहा हूं और SqlServer की प्रतिक्रियाओं को सीमित कर रहा हूं। यदि ओपी या कोई अन्य पाठक इस कोर अवधारणा के गुणों पर अन्य प्लेटफार्मों पर चर्चा करना चाहते हैं, तो हमें इसे प्रति प्लेटफॉर्म पर एक बार चर्चा करनी चाहिए। यह एक कार्टेसियन में शामिल होने के लिए हानिकारक है, एक पृष्ठ पर बातचीत के कई अलग-अलग धागे होंगे।
jcolebrand

जवाबों:


25

यह उत्तर मूल प्रश्न के लिए मददगार साबित हो सकता है लेकिन मुख्य रूप से अन्य पोस्टों में गलत जानकारी को संबोधित करना है। यह BOL में बकवास के एक भाग को भी उजागर करता है।

और जैसा कि INSERT प्रलेखन के लिए कहा गया है , यह मेज पर एक विशेष लॉक का अधिग्रहण करेगा। तालिका के विरुद्ध एक चयन का एकमात्र तरीका NOLOCK का उपयोग करना या लेन-देन का अलगाव स्तर निर्धारित करना है।

BOL राज्यों का जुड़ा हुआ भाग:

एक INSERT विवरण हमेशा उस तालिका में एक अनन्य (X) लॉक प्राप्त करता है जिसे वह संशोधित करता है, और लेनदेन पूरा होने तक उस लॉक को रखता है। अनन्य (एक्स) लॉक के साथ, कोई अन्य लेनदेन डेटा को संशोधित नहीं कर सकता है; रीड ऑपरेशंस केवल NOLOCK संकेत के उपयोग के साथ हो सकते हैं या बिना पढ़े हुए आइसोलेशन स्तर को पढ़ सकते हैं। अधिक जानकारी के लिए, डेटाबेस इंजन में लॉकिंग देखें ।

NB: 2014-8-27 के अनुसार BOL को ऊपर उद्धृत गलत कथनों को हटाने के लिए अद्यतन किया गया है।

शुक्र है कि ऐसा नहीं है। यदि यह एक तालिका में आवेषण थे तो क्रमिक रूप से घटित होंगे और सभी पाठक पूरी तालिका से तब तक अवरुद्ध रहेंगे जब तक कि सम्मिलित लेन-देन पूरा नहीं हो जाता। यह SQL सर्वर को NTFS के रूप में डेटाबेस सर्वर के रूप में कुशल बनाता है। बहुत नहीं।

आम समझ से पता चलता है कि ऐसा नहीं हो सकता लेकिन पॉल रान्डेल बताते हैं, " अपने आप पर एक एहसान करो, किसी पर भरोसा मत करो "। अगर आप BOL सहित किसी पर भी भरोसा नहीं कर सकते , तो मुझे लगता है कि हमें इसे साबित करना होगा।

एक डेटाबेस बनाएँ और पंक्तियों के एक समूह के साथ एक डमी तालिका को पॉपुलेट करें, ध्यान दें कि डेटाबेसआईड वापस नहीं आया।

SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;

USE [master]
GO

IF EXISTS (SELECT name FROM sys.databases WHERE name = N'LockDemo')
DROP DATABASE [LockDemo]
GO

DECLARE @DataFilePath NVARCHAR(4000)
SELECT 
    @DataFilePath = SUBSTRING(physical_name, 1, CHARINDEX(N'master.mdf', LOWER(physical_name)) - 1)
FROM 
    master.sys.master_files
WHERE 
    database_id = 1 AND file_id = 1

EXEC ('
CREATE DATABASE [LockDemo] ON  PRIMARY 
( NAME = N''LockDemo'', FILENAME = N''' + @DataFilePath + N'LockDemo.mdf' + ''', SIZE = 2MB , MAXSIZE = UNLIMITED, FILEGROWTH = 2MB )
 LOG ON 
( NAME = N''LockDemo_log'', FILENAME = N''' + @DataFilePath + N'LockDemo_log.ldf' + ''', SIZE = 1MB , MAXSIZE = UNLIMITED , FILEGROWTH = 1MB )
')

GO

USE [LockDemo]
GO

SELECT DB_ID() AS DatabaseId

CREATE TABLE [dbo].[MyTable]
(
    [id] [int] IDENTITY(1,1) PRIMARY KEY CLUSTERED
    , [filler] CHAR(4030) NOT NULL DEFAULT REPLICATE('A', 4030) 
)
GO

INSERT MyTable DEFAULT VALUES;
GO 100

एक प्रोफाइलर ट्रेस सेट करें जो लॉक को ट्रैक करेगा: अधिग्रहित और लॉक: जारी की गई घटनाएं, पिछली स्क्रिप्ट से डेटाबेसआईड पर फ़िल्टर करना, फ़ाइल के लिए एक पथ सेट करना और ट्रेसआईड को नोट करना।

declare @rc int
declare @TraceID int
declare @maxfilesize BIGINT
declare @databaseid INT
DECLARE @tracefile NVARCHAR(4000)

set @maxfilesize = 5 
SET @tracefile = N'D:\Temp\LockTrace'
SET @databaseid = 9

exec @rc = sp_trace_create @TraceID output, 0, @tracefile, @maxfilesize, NULL 
if (@rc != 0) goto error

declare @on bit
set @on = 1
exec sp_trace_setevent @TraceID, 24, 32, @on
exec sp_trace_setevent @TraceID, 24, 1, @on
exec sp_trace_setevent @TraceID, 24, 57, @on
exec sp_trace_setevent @TraceID, 24, 3, @on
exec sp_trace_setevent @TraceID, 24, 51, @on
exec sp_trace_setevent @TraceID, 24, 12, @on
exec sp_trace_setevent @TraceID, 60, 32, @on
exec sp_trace_setevent @TraceID, 60, 57, @on
exec sp_trace_setevent @TraceID, 60, 3, @on
exec sp_trace_setevent @TraceID, 60, 51, @on
exec sp_trace_setevent @TraceID, 60, 12, @on
exec sp_trace_setevent @TraceID, 23, 32, @on
exec sp_trace_setevent @TraceID, 23, 1, @on
exec sp_trace_setevent @TraceID, 23, 57, @on
exec sp_trace_setevent @TraceID, 23, 3, @on
exec sp_trace_setevent @TraceID, 23, 51, @on
exec sp_trace_setevent @TraceID, 23, 12, @on

-- DatabaseId filter
exec sp_trace_setfilter @TraceID, 3, 0, 0, @databaseid

-- Set the trace status to start
exec sp_trace_setstatus @TraceID, 1

-- display trace id for future references
select TraceID=@TraceID
goto finish

error: 
select ErrorCode=@rc

finish: 
go

एक पंक्ति डालें और ट्रेस रोकें:

USE LockDemo
GO
INSERT MyTable DEFAULT VALUES
GO
EXEC sp_trace_setstatus 3, 0
EXEC sp_trace_setstatus 3, 2
GO

ट्रेस फ़ाइल खोलें और आपको निम्नलिखित पता लगाना चाहिए:

प्रोफाइलर खिड़की

लिया ताले का क्रम है:

  1. आशय-विशेष ताला MyTable पर
  2. इंटेंट-एक्सक्लूसिव लॉक पेज 1: 211 पर
  3. मान डाला जा रहा है के लिए क्लस्टर इंडेक्स प्रविष्टि पर RangeInsert-NullResource
  4. कुंजी पर विशेष ताला

ताले तब रिवर्स ऑर्डर में जारी किए जाते हैं। किसी भी बिंदु पर मेज पर एक विशेष ताला नहीं लगाया गया है।

लेकिन यह सिर्फ एक बैच डालने है! यही नहीं दो, तीन या दर्जनों समानांतर में चल रहे हैं।

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

उच्च अलगाव के स्तर के बारे में क्या है?

इस विशेष उदाहरण के लिए ठीक उसी ताले को लिया जाता है। मुझ पर भरोसा मत करो, यह कोशिश करो!


2
बहुत सूचनाप्रद। अच्छा काम @Mark!
jcolebrand

0

मैं टी-एसक्यूएल काम ज्यादा नहीं करता, लेकिन डॉक्यूमेंटेशन पढ़ने से ...

यह डिजाइन द्वारा है, जैसा कि बेगिन लेनदेन में कहा गया है :

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

और जैसा कि INSERT प्रलेखन के लिए कहा गया है , यह मेज पर एक विशेष लॉक का अधिग्रहण करेगा। NOLOCKलेन-देन के अलगाव स्तर का उपयोग या सेट करने के लिए तालिका के खिलाफ एक एकमात्र तरीका बनाया जा सकता है ।


4
इससे पहले BOL में बुरी तरह से लिखे गए कथन पर ध्यान नहीं दिया गया था। संसाधन पदानुक्रम के भीतर कुछ पर एक विशेष ताला की आवश्यकता होगी, लेकिन यह निश्चित रूप से हमेशा तालिका नहीं है।
मार्क स्टोरी-स्मिथ

6
डॉक्स के लिए -1 (आपकी गलती नहीं) - यह साबित करना आसान है कि स्नैपशॉट अलगाव में यह सच नहीं है इसलिए कंबल "हमेशा एक अनन्य (एक्स) लॉक को प्राप्त करता है" गलत है। अन्य अलगाव स्तरों के बारे में निश्चित नहीं है।
जैक का कहना है कि topanswers.xyz
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.