ডিফল্ট কনস্ট্রাক্ট, এটি মূল্য?


19

আমি পরবর্তী নিয়মগুলি অনুসরণ করে সাধারণত আমার ডাটাবেসগুলি ডিজাইন করি:

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

CREATE TRIGGER <TriggerName>
ON <MyTable>
[BEFORE | AFTER] INSERT
AS
    IF EXISTS (SELECT 1 
               FROM   inserted
               WHERE  Field1 <> <some_initial_value>
               OR     Field2 <> <other_initial_value>)
    BEGIN
        UPDATE MyTable
        SET    Field1 = <some_initial_value>,  
               Field2 = <other_initial_value>  
        ...  
    END
  • সঞ্চিত পদ্ধতি ব্যবহার করে ডিএমএল কার্যকর করা হয়:

sp_MyTable_Insert(@Field1, @Field2, @Field3, ...);
sp_MyTable_Delete(@Key1, @Key2, ...);
sp_MyTable_Update(@Key1, @Key2, @Field3, ...);

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

হালনাগাদ

আমি বুঝতে পারি যে ডিফল্ট সীমাবদ্ধতা ব্যবহার করে আমি অন্য কাউকে আরও তথ্য দিচ্ছি যা অবশ্যই ডেটাবেস পরিচালনা করতে হবে। তবে আমি বেশিরভাগই পারফরম্যান্সে আগ্রহী।

আমি ধরে নিই যে ডাটাবেসটি সর্বদা ডিফল্ট মানগুলি পরীক্ষা করে, যদি আমি সঠিক মান সরবরাহ করি তবে আমি একই কাজটি দু'বার করছি।

উদাহরণস্বরূপ, ট্রিগার কার্যকর করার মধ্যে ডিফল্ট সীমাবদ্ধতা এড়ানোর কোনও উপায় আছে কি?


1
আপনি যদি আপনার সমস্ত ডিএমএলের জন্য পদ্ধতি ব্যবহার করে থাকেন তবে আমি সেখানে আপনার বৈধতা যুক্তিটি করব। বেস টেবিলগুলিতে অ্যাক্সেস থাকা প্রত্যেককে ভুল করা থেকে বিরত রাখতে সীমাবদ্ধতাগুলি ব্যবহার করুন, তবে ট্রিগারগুলি নাটকীয়ভাবে সন্নিবেশগুলিকে কমিয়ে দেবে।
জোনাথন ফাইট

ট্রিগারগুলিতে আপনি কী বৈধতা করছেন? পরিবর্তে চেক সীমাবদ্ধতা দিয়ে এটি করা যেতে পারে?
মার্টিন স্মিথ

@ মার্টিনস্মিত এটি নির্ভর করে, তবে চেক সীমাবদ্ধতা সর্বদা প্রয়োগ করা হয়, আমাকে প্রাথমিক মানগুলি যেমন ব্যবহারকারী, বর্তমান সময় ইত্যাদির মতো করে নিশ্চিত করা দরকার আমার প্রশ্নগুলির অন্যটি একবার দেখুন: dba.stackexchange.com/questions/164678/…
ম্যাকনেটস

1
আপনি যদি "সাধারণ" উত্তর চান তবে আপনার "সীমাবদ্ধতা" অংশটি সরিয়ে দেওয়া উচিত। এসকিউএলে, সীমাবদ্ধতাগুলি ইনপুট মানগুলি বৈধ করে । তারা একটি ডিফল্ট মান নির্ধারণ করে না । এসকিউএলে "ডিফল্ট সীমাবদ্ধতা" বলে কোনও জিনিস নেই। আমি ট্যাগ যোগ sql-serverএবং tsqlআপনার প্রশ্নের মধ্যে কোড হিসেবে অত্যন্ত যে DBMS নির্দিষ্ট
a_horse_with_no_name

উত্তর:


21

আমি ধরে নিই যে ডাটাবেসটি সর্বদা ডিফল্ট মানগুলি পরীক্ষা করে, যদি আমি সঠিক মান সরবরাহ করি তবে আমি একই কাজটি দু'বার করছি।

ওম, তুমি কেন ধরে নিবে? ;-)। প্রদত্ত ডিফল্ট একটি মান প্রদান করার জন্য বিদ্যমান থাকে যখন তারা যে কলামটি সংযুক্ত থাকে তা INSERTবিবৃতিতে উপস্থিত না থাকে , আমি ঠিক এর বিপরীতটি ধরে নেব: যে সম্পর্কিত কলামটি INSERTবিবৃতিতে উপস্থিত থাকলে সেগুলি সম্পূর্ণ উপেক্ষা করা হবে ।

ভাগ্যক্রমে, প্রশ্নটির এই বক্তব্যের কারণে আমাদের উভয়কেই কিছু অনুমান করার দরকার নেই:

আমি বেশিরভাগই পারফরম্যান্সে আগ্রহী।

কর্মক্ষমতা সম্পর্কে প্রশ্নগুলি প্রায় সর্বদা পরীক্ষামূলক able সুতরাং এসকিউএল সার্ভারকে (এখানে প্রকৃত কর্তৃত্ব) এই প্রশ্নের উত্তর দেওয়ার জন্য আমাদের কেবল একটি পরীক্ষা নিয়ে আসা উচিত।

সেটআপ

নিম্নলিখিত একবার চালান:

SET NOCOUNT ON;

-- DROP TABLE #HasDefault;
CREATE TABLE #HasDefault
(
  [HasDefaultID] INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
  [SomeInt] INT NULL,
  [SomeDate] DATETIME NOT NULL DEFAULT (GETDATE())
);

-- DROP TABLE #NoDefault;
CREATE TABLE #NoDefault
(
  [NoDefaultID] INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
  [SomeInt] INT NULL,
  [SomeDate] DATETIME NOT NULL
);

-- make sure that data file and Tran Log file are grown, if need be, ahead of time:
INSERT INTO #HasDefault ([SomeInt])
  SELECT TOP (2000000) NULL
  FROM   [master].sys.[all_columns] ac1
  CROSS JOIN [master].sys.[all_columns] ac2;

1A এবং 1B স্বতন্ত্রভাবে পরীক্ষাগুলি সম্পাদন করুন, একসাথে নয় যা সময়সীমাকে তত্পর করে। প্রত্যেকের জন্য গড় সময় নির্ধারণের জন্য একাধিকবার চালান।

পরীক্ষা 1 এ

TRUNCATE TABLE #HasDefault;
GO

PRINT '#HasDefault:';
SET STATISTICS TIME ON;
INSERT INTO #HasDefault ([SomeDate])
  SELECT TOP (1000000) '2017-05-15 10:11:12.000'
  FROM   [master].sys.[all_columns] ac1
  CROSS JOIN [master].sys.[all_columns] ac2;
SET STATISTICS TIME OFF;
GO

পরীক্ষা 1 বি

TRUNCATE TABLE #NoDefault;
GO

PRINT '#NoDefault:';
SET STATISTICS TIME ON;
INSERT INTO #NoDefault ([SomeDate])
  SELECT TOP (1000000) '2017-05-15 10:11:12.000'
  FROM   [master].sys.[all_columns] ac1
  CROSS JOIN [master].sys.[all_columns] ac2;
SET STATISTICS TIME OFF;
GO

পরীক্ষাগুলি 2A এবং 2B স্বতন্ত্রভাবে চালিত করুন, একসাথে নয় যা সময়সীমাকে তত্পর করে। প্রত্যেকের জন্য গড় সময় নির্ধারণের জন্য একাধিকবার চালান।

পরীক্ষা 2 এ

TRUNCATE TABLE #HasDefault;
GO

DECLARE @Counter INT = 0,
        @StartTime DATETIME,
        @EndTime DATETIME;

BEGIN TRAN;
--SET STATISTICS TIME ON;
SET @StartTime = GETDATE();
WHILE (@Counter < 100000)
BEGIN
  INSERT INTO #HasDefault ([SomeDate]) VALUES ('2017-05-15 10:11:12.000');
  SET @Counter = @Counter + 1;
END;
SET @EndTime = GETDATE();
--SET STATISTICS TIME OFF;
COMMIT TRAN;
PRINT DATEDIFF(MILLISECOND, @StartTime, @EndTime);

পরীক্ষা 2 বি

TRUNCATE TABLE #NoDefault;
GO

DECLARE @Counter INT = 0,
        @StartTime DATETIME,
        @EndTime DATETIME;

BEGIN TRAN;
--SET STATISTICS TIME ON;
SET @StartTime = GETDATE();
WHILE (@Counter < 100000)
BEGIN
  INSERT INTO #NoDefault ([SomeDate]) VALUES ('2017-05-15 10:11:12.000');
  SET @Counter = @Counter + 1;
END;
SET @EndTime = GETDATE();
--SET STATISTICS TIME OFF;
COMMIT TRAN;
PRINT DATEDIFF(MILLISECOND, @StartTime, @EndTime);

আপনার দেখতে হবে পরীক্ষা 1A এবং 1B এর মধ্যে সময় নির্ধারণের মধ্যে, বা 2A এবং 2B পরীক্ষার মধ্যে কোনও বাস্তব পার্থক্য নেই। সুতরাং, না, কোনও DEFAULTসংজ্ঞায়িত তবে ব্যবহার নেই এমন কোনও পারফরম্যান্স পেনাল্টি নেই ।

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


এবং, এটি আমার কাছে কেবল ঘটেছিল যে DEFAULTসম্পর্কিত কলামটি INSERTবিবৃতিতে উপস্থিত থাকলে একটি পরীক্ষা করা হয় কিনা তা বরং বরং উদ্দেশ্যমূলকভাবে এটি প্রদর্শিত হতে পারে : কেবল একটি অবৈধ মান সরবরাহ করে। নিম্নলিখিত পরীক্ষাটি ঠিক তা করে:

-- DROP TABLE #BadDefault;
CREATE TABLE #BadDefault
(
  [BadDefaultID] INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
  [SomeInt] INT NOT NULL DEFAULT (1 / 0)
);


INSERT INTO #BadDefault ([SomeInt]) VALUES (1234); -- Success!!!
SELECT * FROM #BadDefault; -- just to be sure ;-)



INSERT INTO #BadDefault ([SomeInt]) VALUES (DEFAULT); -- Error:
/*
Msg 8134, Level 16, State 1, Line xxxxx
Divide by zero error encountered.
The statement has been terminated.
*/
SELECT * FROM #BadDefault; -- just to be sure ;-)
GO

আপনি দেখতে পাচ্ছেন, যখন একটি কলাম (এবং একটি মান, মূলশব্দ নয় DEFAULT) সরবরাহ করা হয় তখন ডিফল্টটি 100% উপেক্ষা করা হয়। আমরা এটি জানি কারণ INSERTসফল হয়। তবে যদি ডিফল্টটি ব্যবহার করা হয়, তবে শেষ পর্যন্ত এটি কার্যকর করা হওয়ায় একটি ত্রুটি রয়েছে।


একটি ট্রিগার কার্যকর করার মধ্যে ডিফল্ট বাধা এড়ানোর কোনও উপায় আছে কি?

ডিফল্ট সীমাবদ্ধতাগুলি এড়াতে হবে (কমপক্ষে এই প্রসঙ্গে) সম্পূর্ণ অপ্রয়োজনীয়, পরিপূর্ণতার জন্য এটি লক্ষ করা যায় যে কেবল INSTEAD OFট্রিগারের মধ্যেই কোনও ডিফল্ট সীমাবদ্ধতা "এড়ানো" সম্ভব হবে তবে কোনও ট্রিগারের মধ্যে নয় not ট্রিগার তৈরিAFTER করার জন্য ডকুমেন্টেশন অনুসারে :

ট্রিগার টেবিলে যদি প্রতিবন্ধকতাগুলি উপস্থিত থাকে তবে সেগুলি ট্রিগার নির্বাহের INSTEAD এর পরে এবং আফ্রিকার ট্রিগার মৃত্যুর আগে পরীক্ষা করা হয়। যদি সীমাবদ্ধতাগুলি লঙ্ঘন করা হয়, তবে ট্রিগার ক্রিয়াকলাপগুলি INSTEAD OF ফিরিয়ে আনা হবে এবং AFTER ট্রিগারটি বরখাস্ত করা হবে না।

অবশ্যই, একটি INSTEAD OFট্রিগার ব্যবহারের প্রয়োজন হবে:

  1. ডিফল্ট সীমাবদ্ধতা অক্ষম করা হচ্ছে
  2. একটি AFTERট্রিগার তৈরি করা যা সীমাবদ্ধ করে তোলে

তবে, আমি ঠিক এটি করার পরামর্শ দিচ্ছি না।


1
@ এমসিএনলেটস কোন সমস্যা :-)। এই প্রশ্নটি আসলে কিছু গবেষণা করার দুর্দান্ত সুযোগ দিয়েছে। এবং এটি করার সাথে সাথে, আমি মাইএসকিউএলে পরীক্ষা করার চেষ্টাও করেছি (যেহেতু আপনি মূলত আরডিবিএমএস সম্পর্কে সাধারণভাবে জিজ্ঞাসা করেছিলেন) এবং মাইএসকিউএল-এ ডিফল্টগুলি স্থির হওয়া দরকার, CURRENT_TIMESTAMPডেটটাইম কলামগুলির ব্যতিক্রম ছাড়া কেবল এটিই ব্যতিক্রম । সুতরাং, একটি অবৈধ অভিব্যক্তি ব্যবহারের "সহজ" পরীক্ষাটি সেখানে কাজ করবে না (এবং CREATE TABLEএটির যাচাই হওয়ার পরে একটি অবৈধ মান ব্যবহার করা যাবে না ), এবং পারফরম্যান্স পরীক্ষাটি নির্মাণের আমার কাছে সময় নেই। তবে আমার সন্দেহ যে বেশিরভাগ আরডিবিএমএস তাদের সাথে একই আচরণ করবে।
সলোমন রুটজকি

9

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

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