ট্রিগারটিতে সন্নিবেশিত এবং মুছে ফেলা টেবিলগুলিতে যোগদান করা নৃশংস অভিনয়


12

আমি একটি টেবিলে একটি আপডেট আপডেট পেয়েছি যা একটি নির্দিষ্ট কলামের জন্য সুনির্দিষ্ট মান থেকে অন্য কোনও মানতে পরিবর্তিত হয়। এটি যখন ঘটে, তখন এটি কোনও একক আপডেটের বিবৃতি দিয়ে অন্য টেবিলের সাথে সম্পর্কিত কিছু ডেটা আপডেট করে।

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

IF NOT EXISTS (
    SELECT TOP 1 i.CUSTNMBR
    FROM INSERTED i
        INNER JOIN DELETED d
            ON i.CUSTNMBR = d.CUSTNMBR
    WHERE d.CUSTCLAS = 'Misc'
        AND i.CUSTCLAS != 'Misc'
)
    RETURN

এই ক্ষেত্রে, CUSTNMBR অন্তর্নিহিত সারণীর প্রাথমিক কী। যদি আমি এই টেবিলটিতে একটি বড় আপডেট করি (বলুন, 5000+ সারি), আমি বিবৃতি কলামটি স্পর্শ না করলেও এই বিবৃতিটি বয়সগুলি গ্রহণ করে। আমি প্রোফাইলারটিতে কয়েক মিনিটের জন্য এই বিবৃতিতে এটি স্টল দেখতে পারি।

ফাঁসির পরিকল্পনা উদ্ভট। এটি 3,714 মৃত্যুদণ্ড কার্যকর করা এবং million 18.5 মিলিয়ন আউটপুট সারি সহ একটি sertedোকানো স্ক্যান দেখায়। এটি CUSTCLAS কলামে একটি ফিল্টার দিয়ে চলে। এটি এটি (নেস্টেড লুপের মাধ্যমে) একটি মুছে ফেলা স্ক্যান (CUSTCLAS এ ফিল্টার করা) এর সাথে যোগ দেয়, যা কেবল একবার কার্যকর হয় এবং 5000 টি আউটপুট সারি রয়েছে।

আমি এখানে কী কারণে বোকামি করছি? মনে রাখবেন যে ট্রিগারটি অবশ্যই একাধিক সারি আপডেটগুলি সঠিকভাবে পরিচালনা করবে।

সম্পাদনা :

আমি এটিও এটির মতো লেখার চেষ্টা করেছি (যদি উপস্থিতি অপ্রীতিকর কিছু করে) তবে এটি এখনও ঠিক ততটাই ভয়ঙ্কর।

DECLARE @CUSTNMBR varchar(31)
SELECT TOP 1 @CUSTNMBR = i.CUSTNMBR
FROM INSERTED i
    INNER JOIN DELETED d
        ON i.CUSTNMBR = d.CUSTNMBR
WHERE d.CUSTCLAS = 'Misc'
    AND i.CUSTCLAS != 'Misc'

IF @CUSTNMBR IS NULL
    RETURN

আপনি কি "শীর্ষ 1" থেকে মুক্তি পেতে পারেন? আমি মনে করব যে এটি এমন কিছু ওভারহেডের কারণ হয়ে দাঁড়িয়েছে যা আপনি কেবল একটি একক কেস আছে কিনা তা
খতিয়ে

উত্তর:


10

আপনি স্পষ্ট INNER MERGE JOINবা INNER HASH JOINইঙ্গিতগুলি ব্যবহার করে মূল্যায়ন করতে পারেন তবে প্রদত্ত যে আপনি সম্ভবত এই টেবিলগুলি পরে ট্রিগারটিতে ব্যবহার করছেন আপনি সম্ভবত সূচিযুক্ত টেবিলগুলির বিষয়বস্তু insertedএবং deletedসারণীগুলি সন্নিবেশ করানো #tempএবং এটি দিয়ে সম্পন্ন করার চেয়ে ভাল।

তারা স্বয়ংক্রিয়ভাবে তাদের জন্য তৈরি দরকারী সূচকগুলি পায় না।


ঠিক আছে, এটি প্রবলভাবে গতি বাড়ায়, তবে ক্যাসকেডিং ট্রিগার কার্যকর করার সম্ভাবনা রয়েছে। আমি যদি প্রতিটি ট্রিগারে একই টেম্প টেবিলের নামগুলি (# আই, # ডি) ব্যবহার করি তবে তারা দ্বন্দ্ব বোধ করে। প্রতিটি ট্রিগারে কেবল আলাদা টেম্প টেবিলের নাম ব্যবহারের চেয়ে আরও ভাল / নিরাপদ সমাধান কি আছে?
db2

সারণীর ভেরিয়েবলগুলি ব্যবহার করে মূল্যায়ন CUSTNMBRকরতে পারে (অনন্য ক্লাস্টারড ইনডেক্স তৈরির জন্য প্রাথমিক কী দ্বারা সংজ্ঞায়িত ) এবং OPTION (RECOMPILE)সারিগুলির সংখ্যার অ্যাকাউন্ট নেওয়ার জন্য এটি পেতে ইঙ্গিতটি ব্যবহার করতে পারে বা কেবল একটি নির্দিষ্ট নামকরণ কনভেনশন ব্যবহার করতে পারে যেমন#i_dbo_YourTable
মার্টিন স্মিথ

আমি মনে করি আমি তাদের নামকরণের জন্য স্থির করব #trigger_name_i। যদি আমি টেবিলের ভেরিয়েবলগুলি নিয়ে যাই তবে আমাকে কোডটি আরও স্পষ্টভাবে তৈরি টেবিলগুলির সাথে বিশৃঙ্খলা করতে হবে। আমরা ক্যাসকেডিং ট্রিগার পেয়েছি, তবে পুনরাবৃত্ত ট্রিগারগুলি নয়, তাই আমি মনে করি আমি নিরাপদ থাকব ...
db2

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

@ ক্রিসমিসহ আপনার প্রায়শই প্রয়োজন হবে OPTION (RECOMPILE)যাতে কার্ডিনালিটি বিবেচনায় নেওয়া হয়।
মার্টিন স্মিথ

10

আমি জানি যে এর জবাব দেওয়া হয়েছে তবে এটি সম্প্রতি সক্রিয় হিসাবে পপ আপ হয়েছে এবং আমি লক্ষ লক্ষ সারিযুক্ত টেবিলগুলির জন্য এটির মধ্যেও চলে এসেছি। গৃহীত উত্তরটি ছাড় না দেওয়ার সময়, আমি কমপক্ষে যোগ করতে পারি যে আমার অভিজ্ঞতাটি দেখায় যে অনুরূপ পরীক্ষাগুলি করার সময় ট্রিগার পারফরম্যান্সের একটি মূল কারণটি (এক বা একাধিক কলাম আসলে তাদের মান বদলেছে কিনা তা দেখে) কলামটি (গুলি) হয় কিনা পরীক্ষা করা আসলে UPDATEবক্তব্যের অংশ ছিল । আমি মধ্যে যে তুলনা কলাম পাওয়া insertedএবং deletedটেবিল আসলে ছিল না অংশUPDATE বিবৃতি যে অন্যথায় সেখানে ছিলাম না যদি সেই ক্ষেত্র অংশ ছিল কর্মক্ষমতার উপর একটি বিশাল ড্র্যাগ করাUPDATEবিবৃতি (নির্বিশেষে তাদের মান পরিবর্তিত হচ্ছে)। সেই সমস্ত কাজ কেন (যেমন X সারি জুড়ে N ক্ষেত্রের তুলনা করার জন্য একটি কোয়েরি) নির্ধারণ করার জন্য যে কোনও কলাম পরিবর্তিত হওয়ার সম্ভাব্যতা আপনি যদি যুক্তিযুক্তভাবে রায় দিতে পারেন তবে এটি উপস্থিত না থাকলে স্পষ্টতই সম্ভব নয় যা নির্ধারণ করতে পারে মধ্যে SETধারা UPDATEবিবৃতি।

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

-- exit on updates that do not update the only 3 columns we ETL
IF (
     EXISTS(SELECT 1 FROM DELETED) -- this is an UPDATE (Trigger is AFTER INSERT, UPDATE)
     AND (
            NOT (UPDATE(Column3) OR UPDATE(Column7)
                 OR UPDATE(Column11)) -- the columns we care about are not being updated
            OR NOT EXISTS(
                        SELECT 1
                        FROM INSERTED ins
                        INNER JOIN DELETED del
                                ON del.KeyField1 = ins.KeyField1
                                AND del.KeyField2 = ins.KeyField2
                        WHERE ins.Column3 <> del.Column3
                                 COLLATE Latin1_General_100_CS_AS -- case-sensitive compare
                        OR    ISNULL(ins.Column7, -99) <> 
                                 ISNULL(del.Column7, -99) -- NULLable INT field
                        OR    ins.[Column11] <> del.[Column11] -- NOT NULL INT field
                      )
          )
    )
BEGIN
    RETURN;
END;

এই যুক্তিটি বাকি ট্রিগারটিতে এগিয়ে যাবে যদি:

  1. অপারেশন একটি INSERT
  2. অন্তত প্রাসঙ্গিক ক্ষেত্রের একটিতে আছে SETএকটি ধারা UPDATE এবং এক সারি সেই কলামের অন্তত একটি পরিবর্তিত হয়েছে

NOT (UPDATE...) OR NOT EXISTS()বিজোড় বা পিছনের দিকে চেহারা হতে পারে, কিন্তু এটা করছেন এড়াতে ডিজাইন করা হয়েছে SELECTউপর insertedএবং deletedটেবিল যদি প্রাসঙ্গিক কলাম কেউই অংশ UPDATE

আপনার প্রয়োজনের উপর নির্ভর করে, কলামগুলি বিবৃতিটির অংশ কিনা তা নির্ধারণ করার জন্য COLUMNS_UPDATED () ফাংশনটি আরেকটি বিকল্প UPDATE


1
ভাল পয়েন্ট যে তাদের পরীক্ষা করা উচিত UPDATE(CUSTCLAS)এবং মিথ্যা (+1) হলে পুরো জিনিসটি এড়িয়ে যাওয়া উচিত । আমি মনে করি আপনি সঠিক নন যে আপডেট হওয়া কলামগুলি সারি সংস্করণগুলিতে আপডেট হওয়া হিসাবে তত সহজলভ্য নয়।
মার্টিন স্মিথ

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

আমি এর কাঠামোর দিকে আগে তাকিয়েছি। আমি মনে করতে পারি না আমি এটি করার কোনও ভাল উপায় খুঁজে পেয়েছি বা আমি খুব সহজেই একটি সহজে খুঁজে পেতে সক্ষম স্ট্রিং এবং এর মাধ্যমে একটি বিস্তৃত অনুসন্ধান ব্যবহার tempdbকরেছিDBCC PAGE
মার্টিন স্মিথ

ঠিক আছে. একটি সংক্ষিপ্ত আকারের একক ফাইল সহ একটি উদাহরণে tempdbআমি এই স্ক্রিপ্টটি চেষ্টা করেছিলাম , আউটপুটটি নোটপ্যাডে আটকানো এবং "EEEEEE" অনুসন্ধান করেছি। আমি এখানে স্ক্রিনশট মধ্যে আউটপুট দেখতে । উভয় সারিতে উভয় কলামের সংস্করণ আগে এবং পরে নোট করুন। এখানে আমার উদ্দেশ্যে যথেষ্ট সহজ উপায় কিন্তু যথেষ্ট হতে পারে!
মার্টিন স্মিথ

যদিও tempdbপৃষ্ঠাগুলিতে এর পাশের নয় BBBBBBবা অন্যান্য দীর্ঘ EEEEEE স্ট্রিং রয়েছে DDDDDD। আরও কিছু তদন্ত করতে হতে পারে! যদিও এটি REPLICATEকলটির কারণে ।
মার্টিন স্মিথ

2

আমি উপস্থিত থাকলে পুনরায় লেখার চেষ্টা করতে পারি

IF EXISTS (SELECT TOP 1 i.CUSTNMBR     
            FROM INSERTED i         
            INNER JOIN DELETED d             
            ON i.CUSTNMBR = d.CUSTNMBR and d.custclass = 'Misc'  
            WHERE d.CUSTCLAS <>i.CUSTCLAS)    
BEGIN

--do your triggerstuff here
END

1

http://dave.brittens.org/blog/writing-well-behaved-triggers.html

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

আসল পোস্টটি বেশ কিছুক্ষণ আগে হওয়ায় কেউ এটিকে সহায়ক বলে আশা করছেন ...


-1

নিম্নলিখিত কোডটি এই ট্রিগারটির কার্যকারিতা বাড়িয়ে তুলতে পারে। আমি [কাস্টক্লাস] কলামটির সঠিক তথ্য প্রকারটি জানতাম না তাই আপনার এটিকে সামঞ্জস্য করতে হবে।

DECLARE @i AS TABLE (CUSTNMBR VARCHAR(31) NOT NULL PRIMARY KEY, custclass VARCHAR(10) NOT NULL)
DECLARE @d AS TABLE (CUSTNMBR VARCHAR(31) NOT NULL PRIMARY KEY, custclass VARCHAR(10) NOT NULL)
INSERT INTO @i SELECT CUSTNMBR, custclass FROM inserted
INSERT INTO @d SELECT CUSTNMBR, custclass FROM deleted
IF NOT EXISTS
  (SELECT * FROM @i AS i INNER JOIN @d AS d ON d.CUSTNMBR = i.CUSTNMBR
   WHERE i.custclass <> d.custclass) RETURN

আপনার ট্রিগার কোডে আপনার যদি প্রয়োজন হয় তবে আপনি সন্নিবেশ করা এবং মোছা টেবিলগুলির মেমরি অনুলিপিগুলিতে এইগুলিতে অতিরিক্ত কলামগুলি অন্তর্ভুক্ত করতে পারেন Notice একবারে কয়েকটি সারির চেয়ে বেশি আপডেট করার সময় এই টেবিলগুলির প্রাথমিক কীগুলি যোগদানের কার্য সম্পাদনে ব্যাপকভাবে বৃদ্ধি পাবে। শুভকামনা!

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