সাবসেটের সমষ্টিগুলিতে মডেলিংয়ের সীমাবদ্ধতা?


14

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

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

CREATE TABLE journal_entry (
    id bigserial not null unique, --artificial candidate key
    journal_type_id int references  journal_type(id),
    reference text, -- source document identifier, unique per journal
    date_posted date not null,
    PRIMARY KEY (journal_type_id, reference)
);

CREATE TABLE journal_line (
    entry_id bigint references journal_entry(id),
    account_id int not null references account(id),
    amount numeric not null,
    line_id bigserial not null unique,
    CHECK ((sum(amount) over (partition by entry_id) = 0) -- this won't work
);

অবশ্যই এই ধরনের চেক সীমাবদ্ধতা কখনই কাজ করবে না। এটি প্রতি সারিতে কাজ করে এবং পুরো ডিবিতে পরীক্ষা করতে পারে। সুতরাং এটি সর্বদা ব্যর্থ হবে এবং এটি করতে ধীর হবে।

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

  1. আসল প্রবেশের বই এবং চূড়ান্ত প্রবেশের বইয়ের জেনারেল জেনারেল জেনারেল জেনারেল (জেনারেল জেনারেল জেনারেল জেনারেল) এর মধ্যে পার্থক্য সম্পর্কে অ্যাকাউন্টিং জগতের ধারণা থেকে আমি একটি পৃষ্ঠা ধার করতে পারি। এই বিষয়ে আমি জার্নাল এন্ট্রি সংযুক্ত জার্নাল লাইনের একটি অ্যারে হিসাবে এটিকে মডেল করতে পারি, অ্যারেতে সীমাবদ্ধতা প্রয়োগ করতে পারি (পোস্টগ্রেএসকিউএল পদগুলিতে, অজানা (je.line_items) থেকে যোগফল (পরিমাণ) = 0 নির্বাচন করুন A একটি ট্রিগার প্রসারিত হতে পারে এবং এগুলি একটি লাইন আইটেম সারণীতে সংরক্ষণ করুন, যেখানে পৃথক কলামের সীমাবদ্ধতাগুলি আরও সহজেই প্রয়োগ করা যেতে পারে এবং যেখানে সূচিপত্রগুলি আরও কার্যকর হতে পারে This এটিই আমি যে দিকে ঝুঁকছি।
  2. আমি একটি সীমাবদ্ধ ট্রিগার কোড করার চেষ্টা করতে পারি যা 0 এর সিরিজের যোগফল সর্বদা 0 হবে এই ধারণা দিয়ে এই প্রতি লেনদেনকে কার্যকর করবে would

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

এই সমস্যাটি সমাধানের অন্যান্য উপায় কি যা প্রতিটি টেবিলে কয়েক মিলিয়ন রেকর্ড পর্যন্ত ছড়িয়ে যায়? আমি কিছু অনুপস্থিত করছি? আমি কি কোন ট্রেড অফ মিস করেছি?

সংস্করণ সম্পর্কে ক্রেগের নীচের বক্তব্যের প্রতিক্রিয়া হিসাবে, সর্বনিম্ন, এটি পোস্টগ্র্রেএসকিউএল ৯.২ এবং উচ্চতর (সম্ভবত 9.1 এবং উচ্চতর, তবে সম্ভবত আমরা সরাসরি 9.2 সহ যেতে পারি) চালাতে হবে।

উত্তর:


13

যেহেতু আমাদের একাধিক সারি বিস্তৃত করতে হবে এটি সাধারণ CHECKবাধা দিয়ে প্রয়োগ করা যায় না

আমরা বাদ পড়ার সীমাবদ্ধতাও উড়িয়ে দিতে পারি । এগুলি একাধিক সারি বিস্তৃত করতে পারে তবে কেবল বৈষম্য পরীক্ষা করে। একাধিক সারি জুড়ে সমষ্টিগুলির মতো জটিল ক্রিয়াকলাপগুলি সম্ভব নয়।

আপনার কেসটি সর্বোত্তমভাবে ফিট করে এমন সরঞ্জামটি হ'ল একটি CONSTRAINT TRIGGER(বা এমনকি একটি সরল TRIGGER- বর্তমান বাস্তবায়নের একমাত্র পার্থক্য হ'ল আপনি ট্রিগারটির সময়কে সামঞ্জস্য করতে পারেন SET CONSTRAINTS

সুতরাং এটি আপনার বিকল্প 2

একবারে আমরা সর্বদা কার্যকর হওয়া সীমাবদ্ধতার উপর নির্ভর করতে পারি, আমাদের আর পুরো টেবিলে চেক করার দরকার নেই। লেনদেনের শেষে - বর্তমান লেনদেনে কেবল সারিগুলি সন্নিবেশ করানো যথেষ্ট - যথেষ্ট। পারফরম্যান্স ঠিক করা উচিত।

এছাড়াও, হিসাবে

অ্যাকাউন্টিং ডেটা কেবলমাত্র পরিশিষ্ট।

... আমাদের কেবল নতুন সন্নিবেশ করা সারিগুলির যত্ন নেওয়া দরকার । (ধরে নেওয়া UPDATEবা DELETEসম্ভব নয়।)

আমি সিস্টেম কলামটি ব্যবহার xidকরি এবং এটি ফাংশনের সাথে তুলনা করি txid_current()- যা xidবর্তমান লেনদেনের ফেরত দেয় । ধরণের তুলনা করতে, ingালাই প্রয়োজন ... এটি যুক্তিসঙ্গতভাবে নিরাপদ হওয়া উচিত। এটি সম্পর্কিত বিবেচনা করুন, পরে একটি নিরাপদ পদ্ধতিতে উত্তর দিন:

ডেমো

CREATE TABLE journal_line(amount int); -- simplistic table for demo

CREATE OR REPLACE FUNCTION trg_insaft_check_balance()
    RETURNS trigger AS
$func$
BEGIN
   IF sum(amount) <> 0
      FROM journal_line 
      WHERE xmin::text::bigint = txid_current()  -- consider link above
         THEN
      RAISE EXCEPTION 'Entries not balanced!';
   END IF;

   RETURN NULL;  -- RETURN value of AFTER trigger is ignored anyway
END;
$func$ LANGUAGE plpgsql;

CREATE CONSTRAINT TRIGGER insaft_check_balance
    AFTER INSERT ON journal_line
    DEFERRABLE INITIALLY DEFERRED
    FOR EACH ROW
    EXECUTE PROCEDURE trg_insaft_check_balance();

স্থগিত , সুতরাং এটি কেবল লেনদেনের শেষে পরীক্ষা করা হয়।

টেস্ট

INSERT INTO journal_line(amount) VALUES (1), (-1);

কাজ করে।

INSERT INTO journal_line(amount) VALUES (1);

ব্যর্থ হলে:

ত্রুটি: প্রবেশের ভারসাম্য নেই!

BEGIN;
INSERT INTO journal_line(amount) VALUES (7), (-5);
-- do other stuff
SELECT * FROM journal_line;
INSERT INTO journal_line(amount) VALUES (-2);
-- INSERT INTO journal_line(amount) VALUES (-1); -- make it fail
COMMIT;

কাজ করে। :)

লেনদেন শেষ হওয়ার আগে যদি আপনার নিজের প্রতিবন্ধকতা প্রয়োগ করতে হয় তবে আপনি লেনদেনের যে কোনও সময়ে এমনকি শুরুতে এটি করতে পারেন:

SET CONSTRAINTS insaft_check_balance IMMEDIATE;

প্লেইন ট্রিগার সহ আরও দ্রুত

যদি আপনি বহু-সারি দিয়ে পরিচালনা করেন তবে INSERTপ্রতি বিবৃতিতে ট্রিগার করা আরও কার্যকর - যা সীমাবদ্ধ ট্রিগারগুলির দ্বারা সম্ভব নয় :

সীমাবদ্ধ ট্রিগারগুলি কেবল নির্দিষ্ট করা যায় FOR EACH ROW

পরিবর্তে একটি সরল ট্রিগার ব্যবহার করুন এবং এতে আগুন FOR EACH STATEMENT...

  • এর বিকল্পটি হারাবেন SET CONSTRAINTS
  • কর্মক্ষমতা অর্জন।

মুছে ফেলা সম্ভব

আপনার মন্তব্যের জবাবে: যদি DELETEসম্ভব হয় তবে আপনি ডিলেটটি হবার পরে পুরো টেবিলের ব্যালেন্স চেক করে অনুরূপ ট্রিগার যুক্ত করতে পারেন । এটি অনেক বেশি ব্যয়বহুল হবে তবে এটি খুব কমই ঘটবে কারণ এটি খুব কমই ঘটে।


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

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

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

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

4

নিম্নলিখিত এসকিউএল সার্ভার সমাধানটিতে কেবল সীমাবদ্ধতা ব্যবহার করা হয়েছে। আমি আমার সিস্টেমে একাধিক জায়গায় একই ধরণের পন্থা ব্যবহার করছি।

CREATE TABLE dbo.Lines
  (
    EntryID INT NOT NULL ,
    LineNumber SMALLINT NOT NULL ,
    CONSTRAINT PK_Lines PRIMARY KEY ( EntryID, LineNumber ) ,
    PreviousLineNumber SMALLINT NOT NULL ,
    CONSTRAINT UNQ_Lines UNIQUE ( EntryID, PreviousLineNumber ) ,
    CONSTRAINT CHK_Lines_PreviousLineNumber_Valid CHECK ( ( LineNumber > 0
            AND PreviousLineNumber = LineNumber - 1
          )
          OR ( LineNumber = 0 ) ) ,
    Amount INT NOT NULL ,
    RunningTotal INT NOT NULL ,
    CONSTRAINT UNQ_Lines_FkTarget UNIQUE ( EntryID, LineNumber, RunningTotal ) ,
    PreviousRunningTotal INT NOT NULL ,
    CONSTRAINT CHK_Lines_PreviousRunningTotal_Valid CHECK 
        ( PreviousRunningTotal + Amount = RunningTotal ) ,
    CONSTRAINT CHK_Lines_TotalAmount_Zero CHECK ( 
            ( LineNumber = 0
                AND PreviousRunningTotal = 0
              )
              OR ( LineNumber > 0 ) ),
    CONSTRAINT FK_Lines_PreviousLine 
        FOREIGN KEY ( EntryID, PreviousLineNumber, PreviousRunningTotal )
        REFERENCES dbo.Lines ( EntryID, LineNumber, RunningTotal )
  ) ;
GO

-- valid subset inserts
INSERT INTO dbo.Lines(EntryID ,
        LineNumber ,
        PreviousLineNumber ,
        Amount ,
        RunningTotal ,
        PreviousRunningTotal )
VALUES(1, 0, 2, 10, 10, 0),
(1, 1, 0, -5, 5, 10),
(1, 2, 1, -5, 0, 5);

-- invalid subset fails
INSERT INTO dbo.Lines(EntryID ,
        LineNumber ,
        PreviousLineNumber ,
        Amount ,
        RunningTotal ,
        PreviousRunningTotal )
VALUES(2, 0, 1, 10, 10, 5),
(2, 1, 0, -5, 5, 10) ;

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

@ ক্রিস: আমি মনে করি এটি পোস্টগ্র্রেসে (ঠিক আছে dbo.এবং মুছে ফেলার পরে GO) ঠিক ঠিক কাজ করে :
স্ক্যুয়েল

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

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

এবং সুরক্ষিত হওয়ার জন্য আপনার আগের লাইনের সাবটোটালটি অনুসন্ধান করার জন্য কোনও ট্রিগারের প্রয়োজন নেই। এটি FK_Lines_PreviousLineবিদেশী কী বাধা দ্বারা যত্ন নেওয়া হয় ।
ypercubeᵀᴹ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.