বিবৃতি ডেডলকিং নিজেই মার্জ করুন


22

আমার নিম্নলিখিত পদ্ধতি রয়েছে (এসকিউএল সার্ভার ২০০৮ আর 2):

create procedure usp_SaveCompanyUserData
    @companyId bigint,
    @userId bigint,
    @dataTable tt_CoUserdata readonly
as
begin

    set nocount, xact_abort on;

    merge CompanyUser with (holdlock) as r
    using (
        select 
            @companyId as CompanyId, 
            @userId as UserId, 
            MyKey, 
            MyValue
        from @dataTable) as newData
    on r.CompanyId = newData.CompanyId
        and r.UserId = newData.UserId
        and r.MyKey = newData.MyKey
    when not matched then
        insert (CompanyId, UserId, MyKey, MyValue) values
        (@companyId, @userId, newData.MyKey, newData.MyValue);

end;

কোম্পানীআইডি, ইউজারআইডি, মাইকি লক্ষ্য সারণির জন্য সম্মিলিত কী গঠন করে। CompanyId একটি পিতামাতার টেবিলে একটি বিদেশী কী। এছাড়াও, একটি ক্লাস্টারযুক্ত সূচক অন আছে CompanyId asc, UserId asc

এটিকে অনেকগুলি বিভিন্ন থ্রেড থেকে ডাকা হয় এবং আমি একই ক্রিয়াকলাপটিকে কল করে বিভিন্ন প্রক্রিয়ার মধ্যে ধারাবাহিকভাবে অচলাবস্থা পাচ্ছি। আমার বোধগম্যতা ছিল raceোকানো / আপডেট রেসের শর্তের ত্রুটি রোধ করার জন্য "উইথ (হোল্ডলক)" প্রয়োজনীয়।

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

এটি কি সঠিক অনুমান?

এই পরিস্থিতি সমাধানের সর্বোত্তম উপায় কোনটি (অর্থাত্ কোনও ডেডলকস নেই, বহু-থ্রেডেড পারফরম্যান্সের সর্বনিম্ন প্রভাব)?

ক্যোয়ারী প্ল্যান চিত্র (আপনি যদি নতুন ট্যাবে চিত্রটি দেখেন তবে এটি পঠনযোগ্য the ছোট আকারের জন্য দুঃখিত))

  • @ তারিখটিতে সর্বাধিক 28 টি সারি রয়েছে।
  • আমি কোডটির মাধ্যমে ফিরে পেয়েছি এবং আমরা এখানে কোনও লেনদেন শুরু করি এমন কোথাও দেখতে পাচ্ছি না।
  • বিদেশী কীটি কেবল মুছে ফেলার জন্য ক্যাসকেডে সেট আপ করা হয়েছে এবং পিতামাতার টেবিল থেকে কোনও মোছা হয়নি।

উত্তর:


12

ঠিক আছে, বেশ কয়েকবার সমস্ত কিছু দেখার পরে, আমি মনে করি যে আপনার প্রাথমিক ধারণাটি সঠিক ছিল। এখানে সম্ভবত যা চলছে তা হ'ল:

  1. MERGE এর ম্যাচের অংশটি ম্যাচের জন্য সূচকটি পরীক্ষা করে, সেই সারিগুলি / পৃষ্ঠাগুলি যেমন যায় তেমন লক করে।

  2. যখন এটি কোনও মিল ছাড়াই একটি সারি থাকে, এটি প্রথমে নতুন সূচক সারিটি সন্নিবেশ করানোর চেষ্টা করবে তাই এটি একটি সারি / পৃষ্ঠার লিখন-লকের জন্য অনুরোধ করবে ...

তবে অন্য ব্যবহারকারী যদি একই সারি / পৃষ্ঠায় 1 ধাপে পৌঁছে যায় তবে প্রথম ব্যবহারকারী আপডেট থেকে অবরুদ্ধ হয়ে যাবে, এবং ...

যদি দ্বিতীয় ব্যবহারকারীর একই পৃষ্ঠায় সন্নিবেশ করা প্রয়োজন হয়, তবে তারা একটি অচলাবস্থায় রয়েছে।

আফাইক, 100% নিশ্চিত হওয়ার একমাত্র উপায় (সহজ) উপায় যে আপনি এই পদ্ধতিটি দিয়ে কোনও অচলাবস্থা অর্জন করতে পারবেন না এবং তা হ'ল মার্জটিতে একটি ট্যাব্লোকএক্স ইঙ্গিত যুক্ত করা, তবে সম্ভবত এটির কার্য সম্পাদনে খুব খারাপ প্রভাব পড়বে।

এটি সম্ভব যে পরিবর্তে একটি ট্যাবলক ইঙ্গিত যুক্ত করা আপনার পারফরম্যান্সের উপর প্রভাব ফেলতে না পারায় সমস্যা সমাধানের পক্ষে যথেষ্ট।

অবশেষে, আপনি প্যাগলক, এক্সলোক বা প্যাগলক এবং এক্সলোক উভয়ই যুক্ত করার চেষ্টা করতে পারেন। আবার যে শক্তি কাজ এবং কর্মক্ষমতা পারে খুব ভয়াবহ না। আপনাকে এটি দেখতে চেষ্টা করতে হবে।


আপনি কি মনে করেন যে স্ন্যাপশট বিচ্ছিন্নতা স্তর (সারি সংস্করণ) এখানে সহায়ক হতে পারে?
মিকেল এরিকসন

হতে পারে. অথবা এটি অচল ব্যতিক্রমগুলিকে সম্মতিযুক্ত ব্যতিক্রমগুলিতে রূপান্তর করতে পারে।
আরবেরি ইয়ং

2
কোনও INSERT স্টেটমেন্টের লক্ষ্যবস্তু একটি টেবিলের উপর ট্যাব্লক ইঙ্গিতটি নির্দিষ্ট করে তা ট্যাবলকএক্স ইঙ্গিত নির্দিষ্ট করার মতোই প্রভাব ফেলে। (সূত্র: msdn.microsoft.com/en-us/library/bb510625.aspx )
tuespetre

31

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

প্রক্রিয়া এ গন্তব্যটি পড়ে, কোনও সারি খুঁজে পায় না এবং '1 'মান সন্নিবেশ করে। এটিতে '1' মানের উপর একচেটিয়া সারি লক রয়েছে। প্রক্রিয়া বি গন্তব্যটি পড়ে, কোনও সারি খুঁজে পায় না এবং '2' মান সন্নিবেশ করে। এটি '2' মানের উপর একচেটিয়া সারি লক ধারণ করে।

এখন প্রক্রিয়া A কে সারি 2 প্রক্রিয়াজাতকরণ করা দরকার, এবং প্রসেস বি এর সারি 1 টি প্রক্রিয়া করা দরকার ither কোনও প্রক্রিয়াই অগ্রগতি করতে পারে না কারণ এটির জন্য একটি লক প্রয়োজন যা অন্য প্রক্রিয়াটির সাথে রাখা একচেটিয়া লকের সাথে সামঞ্জস্য নয়।

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

বিদ্যমান পরিকল্পনা

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

TYPEএকটি ক্লাস্টার অন্তর্ভুক্ত করতে সারণীর ভেরিয়েবলের পুনরায় সংজ্ঞা দেওয়া PRIMARY KEY:

DROP TYPE dbo.CoUserData;

CREATE TYPE dbo.CoUserData
AS TABLE
(
    MyKey   integer NOT NULL PRIMARY KEY CLUSTERED,
    MyValue integer NOT NULL
);

এক্সিকিউশন প্ল্যানটি এখন ক্লাস্টারড ইনডেক্সের একটি স্ক্যান দেখায় এবং স্বাতন্ত্র্য গ্যারান্টি মানে অপ্টিমাইজার নিরাপদে টেবিল স্পুলটি সরিয়ে ফেলতে সক্ষম:

প্রাথমিক কী সহ key

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

সারণির ভেরিয়েবল সংজ্ঞা পরিবর্তন করা যায় না, এর জন্য আরও একটি বিকল্প রয়েছে:

MERGE dbo.CompanyUser AS R
USING 
    (SELECT DISTINCT MyKey, MyValue FROM @DataTable) AS NewData ON
    R.CompanyId = @CompanyID
    AND R.UserID = @UserID
    AND R.MyKey = NewData.MyKey
WHEN NOT MATCHED THEN 
    INSERT 
        (CompanyID, UserID, MyKey, MyValue) 
    VALUES
        (@CompanyID, @UserID, NewData.MyKey, NewData.MyValue)
OPTION (ORDER GROUP);

এটি একটি স্পষ্ট ধরণের প্রবর্তনের ব্যয়ে স্পুল (এবং সারি-ক্রমের ধারাবাহিকতা) নির্মূলকরণও অর্জন করে:

বাছাই পরিকল্পনা

এই পরিকল্পনাটি একই পরীক্ষা ব্যবহার করে কোনও অচলাবস্থা তৈরি করে নি। নীচে প্রজনন স্ক্রিপ্ট:

CREATE TYPE dbo.CoUserData
AS TABLE
(
    MyKey   integer NOT NULL /* PRIMARY KEY */,
    MyValue integer NOT NULL
);
GO
CREATE TABLE dbo.Company
(
    CompanyID   integer NOT NULL

    CONSTRAINT PK_Company
        PRIMARY KEY (CompanyID)
);
GO
CREATE TABLE dbo.CompanyUser
(
    CompanyID   integer NOT NULL,
    UserID      integer NOT NULL,
    MyKey       integer NOT NULL,
    MyValue     integer NOT NULL

    CONSTRAINT PK_CompanyUser
        PRIMARY KEY CLUSTERED
            (CompanyID, UserID, MyKey),

    FOREIGN KEY (CompanyID)
        REFERENCES dbo.Company (CompanyID),
);
GO
CREATE NONCLUSTERED INDEX nc1
ON dbo.CompanyUser (CompanyID, UserID);
GO
INSERT dbo.Company (CompanyID) VALUES (1);
GO
DECLARE 
    @DataTable AS dbo.CoUserData,
    @CompanyID integer = 1,
    @UserID integer = 1;

INSERT @DataTable
SELECT TOP (10)
    V.MyKey,
    V.MyValue
FROM
(
    VALUES
        (1, 1),
        (2, 2),
        (3, 3),
        (4, 4),
        (5, 5),
        (6, 6),
        (7, 7),
        (8, 8),
        (9, 9)
) AS V (MyKey, MyValue)
ORDER BY NEWID();

BEGIN TRANSACTION;

    -- Test MERGE statement here

ROLLBACK TRANSACTION;

8

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

আরও তিনটি বিকল্প রয়েছে:

  1. আপনি আপনার সন্নিবেশগুলিকে সিরিয়ালাইজ করতে পারেন যাতে এগুলি সংঘর্ষে না ঘটে: আপনি আপনার লেনদেনের শুরুতে sp_getapplock শুরু করতে পারেন এবং আপনার মার্জ চালানোর আগে একচেটিয়া লক অর্জন করতে পারেন। অবশ্যই এটি পরীক্ষা করার জন্য আপনাকে এখনও চাপ দেওয়া দরকার।

  2. আপনার সমস্ত সন্নিবেশগুলিতে আপনার কাছে একটি থ্রেড হ্যান্ডেল থাকতে পারে যাতে আপনার অ্যাপ্লিকেশন সার্ভার সম্মতিটি পরিচালনা করে।

  3. ডেডলকগুলির পরে আপনি স্বয়ংক্রিয়ভাবে পুনরায় চেষ্টা করতে পারেন - যদি চুক্তিটি বেশি হয় তবে এটি সবচেয়ে ধীরতম পদ্ধতির হতে পারে।

যে কোনও উপায়ে, কেবলমাত্র আপনিই আপনার সমাধানটির কার্য সম্পাদনের প্রভাব নির্ধারণ করতে পারবেন।

সাধারণত আমাদের সিস্টেমে মোটেও অচলাবস্থা নেই, যদিও আমাদের সেগুলি রাখার অনেক সম্ভাবনা রয়েছে। ২০১১ সালে আমরা একটি মোতায়েন করতে ভুল করেছিলাম এবং কয়েক ঘন্টার মধ্যে অর্ধ ডজন অচলাবস্থার ঘটনা ঘটেছিল, সমস্ত একই পরিস্থিতি অনুসরণ করে। আমি তাড়াতাড়ি স্থির করেছি এবং এটি বছরের জন্য সমস্ত অচল।

আমরা আমাদের সিস্টেমে বেশিরভাগ পদ্ধতির ব্যবহার করি। এটি আমাদের জন্য সত্যই ভাল কাজ করে।


-1

অন্য একটি সম্ভাব্য পন্থা - আমি মাঝে মাঝে উপস্থিত লকিং এবং পারফরম্যান্স সম্পর্কিত সমস্যাগুলিতে মার্জ পেয়েছি - এটি বিকল্প (ম্যাক্সডপ এক্স) ক্যোয়ারী বিকল্পের সাথে খেলতে পারা উচিত may

ম্লান এবং দূরবর্তী অতীতে এসকিউএল সার্ভারের একটি সন্নিবেশ সারি স্তর স্তর লক করার বিকল্প ছিল - তবে এটি একটি মৃত্যুবরণ করেছে বলে মনে হচ্ছে, তবে একটি পরিচয় সহ একটি ক্লাস্টারযুক্ত পিকে অবশ্যই সন্নিবেশকে পরিষ্কার চালানো উচিত।

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