ট্রিগারগুলি ব্যবহার করে সিঙ্ক্রোনাইজেশন


11

আমার পূর্ববর্তী আলোচনার মতো প্রয়োজন রয়েছে:

আমার কাছে দুটি টেবিল রয়েছে [Account].[Balance]এবং [Transaction].[Amount]:

CREATE TABLE Account (
      AccountID    INT
    , Balance      MONEY
);

CREATE TABLE Transaction (
      TransactionID INT
     , AccountID    INT
    , Amount      MONEY
);

যখন কোনও সন্নিবেশ থাকে, [Transaction]টেবিলের বিপরীতে আপডেট বা মুছুন , এর [Account].[Balance]উপর ভিত্তি করে আপডেট করা উচিত [Amount]

এই কাজটি করার জন্য বর্তমানে আমার একটি ট্রিগার রয়েছে:

ALTER TRIGGER [dbo].[TransactionChanged] 
ON  [dbo].[Transaction]
AFTER INSERT, UPDATE, DELETE
AS 
BEGIN
IF  EXISTS (select 1 from [Deleted]) OR EXISTS (select 1 from [Inserted])
    UPDATE [dbo].[Account]
    SET
    [Account].[Balance] = [Account].[Balance] + 
        (
            Select ISNULL(Sum([Inserted].[Amount]),0)
            From [Inserted] 
            Where [Account].[AccountID] = [Inserted].[AccountID]
        )
        -
        (
            Select ISNULL(Sum([Deleted].[Amount]),0)
            From [Deleted] 
            Where [Account].[AccountID] = [Deleted].[AccountID]
        )
END

যদিও এটি কাজ করে বলে মনে হচ্ছে, আমার কাছে প্রশ্ন রয়েছে:

  1. ট্রিগার কি রিলেশনাল ডাটাবেসের এসিডি নীতি অনুসরণ করে? কোনও সন্নিবেশ প্রতিশ্রুতিবদ্ধ হওয়ার সম্ভাবনা রয়েছে তবে ট্রিগার ব্যর্থ হয়েছে?
  2. আমার IFএবং UPDATEবিবৃতিগুলি অদ্ভুত লাগছে। সঠিক [Account]সারিটি আপডেট করার আরও ভাল কোনও উপায় আছে কি ?

উত্তর:


13

1. ট্রিগারটি কি রিলেশনাল ডাটাবেসের এসিডি নীতি অনুসরণ করে? কোনও সন্নিবেশ প্রতিশ্রুতিবদ্ধ হওয়ার সম্ভাবনা রয়েছে তবে ট্রিগার ব্যর্থ হয়েছে?

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

ACID বৈশিষ্ট্য এছাড়াও পুরো লেনদেন (ট্রিগার কোড সহ) গ্যারান্টি একটি রাষ্ট্র যে লঙ্ঘন করে না কোন স্পষ্ট সীমাবদ্ধতার (ইন ডাটাবেসের ছাড়বে সঙ্গতিপূর্ণভাবে ) এবং কোন আদায়যোগ্য অঙ্গীকারবদ্ধ প্রভাব একটি ডাটাবেস ক্র্যাশ (টিকে থাকবে টেকসই )।

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

২. আমার আইএফ এবং আপডেটের বিবৃতিগুলি অদ্ভুত দেখাচ্ছে। সঠিক [অ্যাকাউন্ট] সারিটি আপডেট করার আরও ভাল কোনও উপায় আছে কি?

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

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

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

নমুনা সারণী

CREATE TABLE dbo.Accounts
(
    AccountID integer NOT NULL,
    Balance money NOT NULL,

    CONSTRAINT PK_Accounts_ID
    PRIMARY KEY CLUSTERED (AccountID)
);

CREATE TABLE dbo.Transactions
(
    TransactionID integer IDENTITY NOT NULL,
    AccountID integer NOT NULL,
    Amount money NOT NULL,

    CONSTRAINT PK_Transactions_ID
    PRIMARY KEY CLUSTERED (TransactionID),

    CONSTRAINT FK_Accounts
    FOREIGN KEY (AccountID)
    REFERENCES dbo.Accounts (AccountID)
);

নিরোধক TRUNCATE TABLE

ট্রিগারদের দ্বারা বরখাস্ত করা হয় না TRUNCATE TABLE। নিম্নলিখিত খালি টেবিলটি Transactionsটেবিলটি কেটে ফেলা রোধ করার জন্য বিশুদ্ধরূপে উপস্থিত রয়েছে (বিদেশী কী দ্বারা উল্লেখ করা সারণী কাটা রোধ করে ):

CREATE TABLE dbo.PreventTransactionsTruncation
(
    Dummy integer NULL,

    CONSTRAINT FK_Transactions
    FOREIGN KEY (Dummy)
    REFERENCES dbo.Transactions (TransactionID),

    CONSTRAINT CHK_NoRows
    CHECK (Dummy IS NULL AND Dummy IS NOT NULL)
);

ট্রিগার সংজ্ঞা

নিম্নলিখিত ট্রিগার কোডটি কেবলমাত্র প্রয়োজনীয় অ্যাকাউন্ট এন্ট্রি রক্ষণাবেক্ষণের জন্য নিশ্চিত করে এবং SERIALIZABLEসেখানে শব্দার্থক ব্যবহার করে । পছন্দসই পার্শ্ব-প্রতিক্রিয়া হিসাবে, এটি একটি ভুল ফলাফলও এড়িয়ে যায় যা যদি সারি-সংস্করণ বিচ্ছিন্নকরণ স্তর ব্যবহার করা হয় তবে ফলাফল হতে পারে। যদি সোর্স স্টেটমেন্ট দ্বারা কোনও সারি প্রভাবিত না হয় তবে কোডটি ট্রিগার কোডটি কার্যকর করতেও এড়িয়ে যায়। অস্থায়ী টেবিল এবং RECOMPILEইঙ্গিতটি সঠিক কার্ডিনালটির অনুমানের কারণে সৃষ্ট ট্রিগার এক্সিকিউশন পরিকল্পনার সমস্যা এড়াতে ব্যবহৃত হয়:

CREATE TRIGGER dbo.TransactionChange ON dbo.Transactions 
AFTER INSERT, UPDATE, DELETE 
AS
BEGIN
IF @@ROWCOUNT = 0 OR
    TRIGGER_NESTLEVEL
    (
        OBJECT_ID(N'dbo.TransactionChange', N'TR'),
        'AFTER', 
        'DML'
    ) > 1 
    RETURN;

    SET NOCOUNT, XACT_ABORT ON;

    CREATE TABLE #Delta
    (
        AccountID integer PRIMARY KEY,
        Amount money NOT NULL
    );

    INSERT #Delta
        (AccountID, Amount)
    SELECT 
        InsDel.AccountID,
        Amount = SUM(InsDel.Amount)
    FROM 
    (
        SELECT AccountID, Amount
        FROM Inserted
        UNION ALL
        SELECT AccountID, $0 - Amount
        FROM Deleted
    ) AS InsDel
    GROUP BY
        InsDel.AccountID;

    UPDATE A
    SET Balance += D.Amount
    FROM #Delta AS D
    JOIN dbo.Accounts AS A WITH (SERIALIZABLE)
        ON A.AccountID = D.AccountID
    OPTION (RECOMPILE);
END;

পরীক্ষামূলক

নিম্নলিখিত কোডটি শূন্য ব্যালেন্স সহ 100,000 অ্যাকাউন্ট তৈরি করতে সংখ্যার সারণি ব্যবহার করে :

INSERT dbo.Accounts
    (AccountID, Balance)
SELECT
    N.n, $0
FROM dbo.Numbers AS N
WHERE
    N.n BETWEEN 1 AND 100000;

নীচের পরীক্ষার কোডটি 10,000 টি এলোমেলো লেনদেন সন্নিবেশ করায়:

INSERT dbo.Transactions
    (AccountID, Amount)
SELECT 
    CONVERT(integer, RAND(CHECKSUM(NEWID())) * 100000 + 1),
    CONVERT(money, RAND(CHECKSUM(NEWID())) * 500 - 250)
FROM dbo.Numbers AS N
WHERE 
    N.n BETWEEN 1 AND 10000;

এসকিউএলকিউরিস্ট্রেস সরঞ্জামটি ব্যবহার করে , আমি ভাল পারফরম্যান্স, কোনও ডেডলকস এবং সঠিক ফলাফল সহ 32 টি থ্রেডে 100 বার এই পরীক্ষাটি চালিয়েছি । আমি এখনও এটি শেখার অনুশীলন ব্যতীত অন্য কিছু হিসাবে সুপারিশ করি না।

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