বিপুল INSERT গুলি SELECT গুলি অবরুদ্ধ করছে


14

বিপুল পরিমাণ INSERTs নিয়ে আমার একটি সমস্যা রয়েছে যা আমার নির্বাচন নির্বাচন পরিচালনা করে।

স্কিমা

আমার এই মত একটি টেবিল আছে:

CREATE TABLE [InverterData](
    [InverterID] [bigint] NOT NULL,
    [TimeStamp] [datetime] NOT NULL,    
    [ValueA] [decimal](18, 2) NULL,
    [ValueB] [decimal](18, 2) NULL
    CONSTRAINT [PrimaryKey_e149e28f-5754-4229-be01-65fafeebce16] PRIMARY KEY CLUSTERED 
    (
        [TimeStamp] DESC,
        [InverterID] ASC
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF
    , IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON
    , ALLOW_PAGE_LOCKS = ON)
)

আমার কাছে এই সামান্য সহায়ক পদ্ধতিও রয়েছে, যা আমাকে MERGE কমান্ডের সাথে সন্নিবেশ বা আপডেট (সংঘাতের বিষয়ে আপডেট) করতে দেয়:

CREATE PROCEDURE [InsertOrUpdateInverterData]
    @InverterID bigint, @TimeStamp datetime
    , @ValueA decimal(18,2), @ValueB decimal(18,2)
AS
BEGIN
    MERGE [InverterData] AS TARGET
        USING (VALUES (@InverterID, @TimeStamp, @ValueA, @ValueB))
        AS SOURCE ([InverterID], [TimeStamp], [ValueA], [ValueB])
        ON TARGET.[InverterID] = @InverterID AND TARGET.[TimeStamp] = @TimeStamp
    WHEN MATCHED THEN
        UPDATE
        SET [ValueA] = SOURCE.[ValueA], [ValueB] = SOURCE.[ValueB]              
    WHEN NOT MATCHED THEN
        INSERT ([InverterID], [TimeStamp], [ValueA], [ValueB]) 
        VALUES (SOURCE.[InverterID], SOURCE.[TimeStamp], SOURCE.[ValueA], SOURCE.[ValueB]);
END

ব্যবহার

আমার কাছে এখন একাধিক সার্ভারে পরিষেবা দৃষ্টান্ত রয়েছে যা [InsertOrUpdateInverterData]পদ্ধতিটি দ্রুত কল করে ব্যাপক আপডেটগুলি করে ।

এছাড়াও একটি ওয়েবসাইট রয়েছে যা [InverterData]টেবিলে সलेक्ट নির্বাচন করে ।

সমস্যা

আমি যদি [InverterData]টেবিলের উপরে নির্বাচনগুলি অনুসন্ধান করি তবে সেগুলি বিভিন্ন টাইমস্প্যানগুলিতে অগ্রসর হয়, আমার পরিষেবা দৃষ্টান্তের INSERT ব্যবহারের উপর নির্ভর করে। আমি যদি সমস্ত পরিষেবাদির উদাহরণগুলিতে বিরতি দিই তবে নির্বাচনটি বিদ্যুত দ্রুত হয়, উদাহরণটি যদি দ্রুত সন্নিবেশ করায় সেলেপগুলি সত্যই ধীর বা এমনকি একটি সময়সীমা বাতিল হয়ে যায়।

প্রচেষ্টা

আমি [sys.dm_tran_locks]লকিংয়ের প্রক্রিয়াগুলি অনুসন্ধানের জন্য টেবিলে কয়েকটি নির্বাচন করেছি

SELECT
tl.request_session_id,
wt.blocking_session_id,
OBJECT_NAME(p.OBJECT_ID) BlockedObjectName,
h1.TEXT AS RequestingText,
h2.TEXT AS BlockingText,
tl.request_mode

FROM sys.dm_tran_locks AS tl

INNER JOIN sys.dm_os_waiting_tasks AS wt ON tl.lock_owner_address = wt.resource_address
INNER JOIN sys.partitions AS p ON p.hobt_id = tl.resource_associated_entity_id
INNER JOIN sys.dm_exec_connections ec1 ON ec1.session_id = tl.request_session_id
INNER JOIN sys.dm_exec_connections ec2 ON ec2.session_id = wt.blocking_session_id
CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2

এটি ফলাফল:

এখানে চিত্র বর্ণনা লিখুন

এস = ভাগ করা হয়েছে। অধিবেশন অধিবেশনটি রিসোর্সে অংশীদারি অ্যাক্সেস মঞ্জুর করা হয়।

প্রশ্ন

[InsertOrUpdateInverterData]যে নির্বাচনগুলি কেবল MERGE কমান্ড ব্যবহার করছে সেগুলি দ্বারা কেন বাছাইকৃতগুলি অবরুদ্ধ করা হচ্ছে?

এর ভিতরে সংজ্ঞায়িত বিচ্ছিন্নতা মোডের সাথে আমাকে কি কোনও ধরণের লেনদেন ব্যবহার করতে হবে [InsertOrUpdateInverterData]?

আপডেট 1 (@ পল এর প্রশ্নের সাথে সম্পর্কিত)

[InsertOrUpdateInverterData]নিম্নলিখিত পরিসংখ্যান সম্পর্কে এমএস-এসকিউএল সার্ভারের অভ্যন্তরীণ প্রতিবেদনের ভিত্তিতে :

  • গড় সিপিইউ-সময়: 0.12 মিমি
  • গড় পঠন প্রক্রিয়া: 5. / প্রতি প্রতি
  • গড় লেখার প্রক্রিয়া: 0 / প্রতি প্রতি

এটির ভিত্তিতে দেখে মনে হচ্ছে মার্জ কমান্ডটি বেশিরভাগই পঠন ক্রিয়ায় ব্যস্ত যা টেবিলটি লক করে দেবে! (?)

আপডেট 2 (@ পল এর প্রশ্নের সাথে সম্পর্কিত)

[InverterData]টেবিল হিসাবে স্টোরেজ পরিসংখ্যান অনুসরণ করেনি:

  • ডেটা স্পেস: 26,901.86 এমবি
  • সারি গণনা: 131,827,749
  • বিভাজন: সত্য
  • পার্টিশন গণনা: 62

এখানে (সর্বমোট) সম্পূর্ণ এসপি_হোআইএসএটিভ রেজাল্ট সেট:

SELECT হুকুম

  • ডিডি এইচ: মিমি: এসএস.এমএস: 00 00: 01: 01.930
  • সেশন_আইডি: 73
  • ওয়েট_ইনফো: (12629 মিমি) এলসিকে_এমএস
  • সিপিইউ: 198
  • ব্লকিং_অ্যাসিওন_আইডি: 146
  • পঠিত: 99,368
  • লিখেছেন: 0
  • স্থিতি: স্থগিত
  • ওপেন_ট্রান_কাউন্ট: 0

[InsertOrUpdateInverterData]কমান্ড অবরুদ্ধ

  • ডিডি এইচ: মিমি: এসএস.এমএস: 00 00: 00: 00.330
  • সেশন_আইডি: 146
  • ওয়েট_ইনফো: নুল
  • সিপিইউ: 3,972
  • ব্লকিং_অ্যাসিওন_আইডি: নুল
  • পঠন: 376,95
  • লিখেছেন: 126
  • স্থিতি: ঘুমানো
  • ওপেন_ট্রাণ_কাউন্ট: ১

([TimeStamp] DESC, [InverterID] ASC)সৌন্দর্য ক্লাস্টার সূচির জন্য একটি অদ্ভুত পছন্দ পছন্দ করি। আমি DESCঅংশ বলতে চাই ।
ypercubeᵀᴹ

আমি আপনার বক্তব্যটি বুঝতে পারি: ক্লাস্টারড ইনডেক্স ডিএসসি তথ্য সন্নিবেশ করানো টেবিলটি পুনরায় বিল্ডিংয়ের পরিবর্তে শেষের দিকে যুক্ত করবে ... কর্মক্ষমতা কুকুর; পুনর্নির্মাণের সময় টেবিলটি লক করা হবে ... হ্যাঁ। জোভ দ্বারা, আপনি এটি আছে। কাঠামোটি লকগুলির চেয়ে বেশি লক করার কারণ।
Alocyte

উত্তর:


12

প্রথমত, যদিও মূল প্রশ্নের সাথে কিছুটা সম্পর্কিত নয়, আপনার MERGEবিবৃতিটি কোনও রেসের শর্তের কারণে ত্রুটিগুলির ঝুঁকিতে রয়েছে । সংক্ষেপে সমস্যাটি হ'ল একাধিক সমবর্তী থ্রেডের পক্ষে এই সিদ্ধান্তে পৌঁছানো সম্ভব যে লক্ষ্য সারিটির অস্তিত্ব নেই, ফলস্বরূপ collোকানোর চেষ্টা সংঘর্ষে পরিণত হয়। এর মূল কারণটি হ'ল অস্তিত্ব নেই এমন কোনও সারিতে ভাগ করা বা আপডেট লক নেওয়া সম্ভব নয়। সমাধানটি একটি ইঙ্গিত যুক্ত করা:

MERGE [dbo].[InverterData] WITH (SERIALIZABLE) AS [TARGET]

Serializable বিচ্ছিন্নতা স্তর ইঙ্গিত কী পরিসর যেখানে সারি যেতে হবে লক করা আছে নিশ্চিত। রেঞ্জ লকিং সমর্থন করার জন্য আপনার কাছে একটি অনন্য সূচক রয়েছে, সুতরাং এই ইঙ্গিতটি লক করাতে বিরূপ প্রভাব ফেলবে না, আপনি কেবল এই সম্ভাব্য রেস শর্তের বিরুদ্ধে সুরক্ষা পাবেন।

মূল প্রশ্ন

SELECTs[InsertOrUpdateInverterData] প্রক্রিয়া যে কেবল MERGEকমান্ড ব্যবহার করছে তা দ্বারা কেন অবরুদ্ধ ?

ডিফল্ট লকিং পড়ার জন্য প্রতিশ্রুতিবদ্ধ বিচ্ছিন্নতা স্তরের অধীনে, ডেটা পড়ার সময় ভাগ করা (এস) লকগুলি নেওয়া হয়, এবং সাধারণত পড়া শেষ হওয়ার সাথে সাথেই (যদিও সর্বদা তা নয়) প্রকাশিত হয়। কিছু ভাগ করা লক বিবৃতি শেষে রাখা হয়।

একটি MERGEবিবৃতি ডেটা পরিবর্তন করে, সুতরাং এটি পরিবর্তন করতে ডেটা সনাক্ত করার সময় এস বা আপডেট (ইউ) লকগুলি অর্জন করবে, যা প্রকৃত পরিবর্তন সম্পাদনের ঠিক আগে একচেটিয়া (এক্স) লকে রূপান্তরিত হয়। উভয় ইউ এবং এক্স লক অবশ্যই লেনদেনের শেষ পর্যন্ত ধরে রাখা উচিত।

এটি 'আশাবাদী' স্ন্যাপশট বিচ্ছিন্নতা (এসআই) না বাদে সমস্ত বিচ্ছিন্ন স্তরের অধীনে সত্য - সংস্করণ পড়ার প্রতিশ্রুতিযুক্তকে বিভ্রান্ত করার জন্য, এটি রিড কমিটেড স্ন্যাপশট বিচ্ছিন্নতা (আরসিএসআই) নামেও পরিচিত ।

আপনার প্রশ্নের কোনও কিছুই ইউ এস লক ধারণ করে থাকা কোনও সেশন দ্বারা এস এস লক হওয়ার অপেক্ষারত একটি সেশন দেখায় না। এই লকগুলি সামঞ্জস্যপূর্ণ । যে কোনও ব্লকিং অবশ্যই একটি হ'ল এক্স লকটিতে ব্লক করার কারণে ঘটছে। সংক্ষিপ্ত সময়ের ব্যবধানে যখন বিপুল সংখ্যক স্বল্প-মেয়াদী লকগুলি নেওয়া, রূপান্তর করা এবং ছেড়ে দেওয়া হচ্ছে তখন এটি ক্যাপচার করা কিছুটা জটিল হতে পারে।

open_tran_count: 1InsertOrUpdateInverterData কমান্ড উপর তদন্ত মূল্য। যদিও কমান্ডটি খুব বেশি দিন চলছিল না, আপনার পরীক্ষা করা উচিত যে আপনার অকারণে দীর্ঘতর কোনও লেনদেন (প্রয়োগ বা উচ্চ-স্তরের সঞ্চিত পদ্ধতিতে) নেই। সেরা অনুশীলন হ'ল লেনদেন যতটা সম্ভব সংক্ষিপ্ত রাখা। এটি কিছুই নাও হতে পারে তবে আপনার অবশ্যই পরীক্ষা করা উচিত।

সম্ভাব্য সমাধান

কিন যেমন একটি মন্তব্যে পরামর্শ দিয়েছে, আপনি এই ডাটাবেসে একটি সারি-সংস্করণ বিচ্ছিন্নকরণ স্তর (আরসিএসআই বা এসআই) সক্ষম করতে পারেন । আরসিএসআই সবচেয়ে বেশি ব্যবহৃত হয়, কারণ এটি সাধারণত অ্যাপ্লিকেশন পরিবর্তনের জন্য প্রয়োজন হয় না। একবার সক্ষম হয়ে গেলে ডিফল্ট পাঠ্য প্রতিশ্রুতিবদ্ধ বিচ্ছিন্নতা স্তর পাঠগুলির জন্য এস লক নেওয়ার পরিবর্তে সারি সংস্করণ ব্যবহার করে, তাই এসএক্স ব্লকিং হ্রাস বা বাদ দেওয়া হয়। কিছু ক্রিয়াকলাপ (যেমন বিদেশী কী চেক) এখনও আরসিএসআইয়ের অধীনে এস লকগুলি অর্জন করে।

সচেতন থাকুন যে সারি সংস্করণগুলি মোড়কগুলি পরিবর্তনের ক্রিয়াকলাপের হার এবং লেনদেনের দৈর্ঘ্যের আনুপাতিকভাবে কথা বলে টেম্পডিডিবি স্থান ব্যবহার করে। আপনার ক্ষেত্রে আরসিএসআই (বা এসআই) এর প্রভাবটি বোঝার জন্য এবং বোঝার জন্য আপনার প্রয়োগের পুরোপুরি পরীক্ষা করা দরকার ।

আপনি যদি পুরো কাজের চাপের জন্য এটি সক্ষম করার পরিবর্তে আপনার সংস্করণটির ব্যবহার স্থানীয় করতে চান তবে এসআই আরও ভাল পছন্দ হতে পারে। পড়ার লেনদেনের জন্য এসআই ব্যবহার করে আপনি পাঠক এবং লেখকদের মধ্যে ঝগড়া এড়াতে পারবেন, পাঠকদের ব্যয় অনুসারে যে কোনও সমবর্তী পরিবর্তন শুরু হওয়ার আগে সারিটির সংস্করণটি দেখুন (আরও সঠিকভাবে, এসআই এর অধীনে পঠন অপারেশন সর্বদা প্রতিশ্রুতিবদ্ধ অবস্থা দেখতে পাবে এসআই লেনদেন শুরু হওয়ার সময় সারি)। লেখার লেনদেনের জন্য এসআই ব্যবহার করার খুব কম বা কোনও লাভ নেই, কারণ লেখার লকগুলি এখনও নেওয়া হবে এবং আপনার কোনও লেখার বিরোধগুলি পরিচালনা করতে হবে। যা না চাইলে আপনি :)

দ্রষ্টব্য: আরসিএসআইয়ের বিপরীতে (যা একবার সক্ষম হয়ে পড়ার প্রতিশ্রুতিতে চলতে থাকা সমস্ত লেনদেনের ক্ষেত্রে প্রযোজ্য), এসআইকে স্পষ্টভাবে ব্যবহার করে অনুরোধ করতে হবে SET TRANSACTION ISOLATION SNAPSHOT;

সূক্ষ্ম আচরণ যা পাঠকদের অবরুদ্ধ লেখকদের উপর নির্ভর করে (ট্রিগার কোড সহ!) পরীক্ষাটি প্রয়োজনীয় করে তোলে। বিশদের জন্য আমার লিঙ্কিত নিবন্ধের সিরিজ এবং বই অনলাইন দেখুন। আপনি যদি আরসিএসআইয়ের বিষয়ে সিদ্ধান্ত নেন, বিশেষত পড়ুন প্রতিশ্রুতিবদ্ধ স্ন্যাপশট বিচ্ছিন্নকরণের অধীনে ডেটা পরিবর্তনগুলি পর্যালোচনা করতে ভুলবেন না ।

অবশেষে, আপনার অবশ্যই নিশ্চিত হওয়া উচিত যে আপনার দৃষ্টান্তটি এসকিউএল সার্ভার 2008 সার্ভিস প্যাক 4-এ সজ্জিত।


0

বিনীতভাবে, আমি মার্জ ব্যবহার করব না। আমি যদি অস্তিত্বগুলি (আপডেট) ইলএসই (INSERT) এর সাথে যেতে পারি - সারিগুলি সনাক্ত করতে আপনি যে দুটি কলাম ব্যবহার করছেন তার একটি ক্লাস্টার কী রয়েছে যাতে এটি একটি সহজ পরীক্ষা।

আপনি ম্যাসিভ সন্নিবেশ উল্লেখ করেছেন এবং তবুও 1 দ্বারা 1 করছেন ... স্টেজিং টেবিলটিতে ডেটা ব্যাচিংয়ের এবং পাওয়ার ওভারওয়াল্ডিং এসকিউএল ডেটা সেট করে একবারে 1 টির বেশি আপডেট / সন্নিবেশ করার ক্ষমতা সেট ব্যবহার করার কথা ভাবেন ? মঞ্চ টেবিলে কন্টেন্টের জন্য রুটিন পরীক্ষা করা পছন্দ করুন এবং একবারে 1 এর পরিবর্তে একবারে শীর্ষ 10000 কে ধরে নেওয়া ...

আমি আমার আপডেটে এই জাতীয় কিছু করব

DECLARE @Set TABLE (StagingKey, ID,DATE)
INSERT INTO @Set
UPDATE Staging 
SET InProgress = 1
OUTPUT StagingKey, Staging.ID, Staging.Date
WHERE InProgress = 0
AND StagingID IN (SELECT TOP (100000) StagingKey FROM Staging WHERE inProgress = 0 ORDER BY StagingKey ASC ) --FIFO

DECLARE @Temp 
INSERT INTO @TEMP 
UPDATE [DEST] SET Value = Staging.Value [whatever]
OUTPUT INSERTED.ID, DATE [row identifiers]
FROM [DEST] 
JOIN [STAGING]
JOIN [@SET]; 
INSERT INTO @TEMP 
INSERT [DEST] 
SELECT
OUTPUT INSERT.ID, DATE [row identifiers] 
FROM [STAGING] 
JOIN [@SET] 
LEFT JOIN [DEST]

UPDATE Staging
SET inProgress = NULL
FROM Staging 
JOIN @set
ON @Set.Key = Staging.Key
JOIN @temp
ON @temp.id = @set.ID
AND @temp.date = @set.Date

আপনি সম্ভবত আপডেট ব্যাচ পপিং একাধিক কাজ চালাতে পারেন, এবং আপনার একটি ট্রিপল মুছা চলমান একটি পৃথক কাজ প্রয়োজন

while exists (inProgress is null) 
delete top (100) from staging where inProgress is null 

মঞ্চ টেবিল পরিষ্কার করতে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.