8 মিনিট

প্রথম মাইগ্রেশনের আগে PostgreSQL স্কিমা যাচাই

PostgreSQL স্কিমা যাচাই প্রথম মাইগ্রেশন ডেটায় হাত দেওয়ার আগেই ভুল ম্যাপিং, দুর্বল কনস্ট্রেইন্ট, অনুপস্থিত ইনডেক্স এবং অনিরাপদ পরিবর্তন শনাক্ত করে।

প্রথম মাইগ্রেশনের আগে PostgreSQL স্কিমা যাচাই

একটি AI বিল্ডার বৈধ PostgreSQL তৈরি করতে পারে, তবু ভুল ডেটাবেস অনুমান করতে পারে। সিনট্যাক্স সহজ অংশ। বিপজ্জনক ভুলগুলো বেশ বিশ্বাসযোগ্য শোনায়: ঐচ্ছিক সম্পর্ক বাধ্যতামূলক হয়ে যায়, স্ট্যাটাস স্ট্রিংয়ে অসম্পূর্ণ CHECK কনস্ট্রেইন্ট বসে, এমন রেকর্ডেও ডিলিশন ক্যাসকেড হয় যেগুলো টিকে থাকার কথা, অথবা মাইগ্রেশন টেবিল আবার তৈরি করে নীরবে একটি কলাম হারিয়ে ফেলে।

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

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

অনুমিত স্কিমা অবিশ্বস্ত স্পেসিফিকেশন

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

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

একটি CREATE TABLE স্টেটমেন্ট কাঙ্ক্ষিত চূড়ান্ত কাঠামো ঠিকভাবে বর্ণনা করতে পারে, কিন্তু সেখানে পৌঁছানোর কাজগুলো অনিরাপদ হতে পারে। ধরুন বিল্ডার customer_name text বদলে customer_id bigint করছে। শেষের ফোরেন কি যুক্তিসঙ্গত হতে পারে, কিন্তু ঐতিহাসিক নামকে কাস্টমারের সঙ্গে মেলানোর আগে নামের কলাম ফেলে দেওয়া মাইগ্রেশন সেই মিলের একমাত্র প্রমাণ নষ্ট করে। স্কিমা পর্যালোচনা গন্তব্য অনুমোদন করে, মাইগ্রেশন পর্যালোচনা পথটি দেখে।

প্রস্তাবিত মডেলটি ডোমেইনের ভাষায় জোরে পড়ে দেখুন। invoices.customer_id যে customers.id রেফারেন্স করে, এভাবে না বলে বলুন যে প্রতিটি ইনভয়েস ঠিক একজন আইনগত কাস্টমারের। প্রথম বাক্যটি দরকারি আপত্তির সুযোগ দেয়: কাস্টমার বাছাইয়ের আগে খসড়া থাকতে পারে, আমদানি করা ইনভয়েস আর্কাইভ করা কাস্টমারকে উল্লেখ করতে পারে, আর আইনগত নথিতে ইস্যুর সময়ের কাস্টমারের নাম স্থির রাখা লাগতে পারে। SQL-এর ভাষা এসব মতভেদ আড়াল করতে পারে।

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

পরিচিত রেকর্ড ভুল টেবিল ম্যাপিং প্রকাশ করে

পরিচিত ডেটাসেটে অর্থগত বৈচিত্র্যের জন্য বাছাই করা রেকর্ড থাকা উচিত, কারণ বড় র‌্যান্ডম নমুনায় প্রায়ই একই সহজ কেস বারবার আসে। প্রায় একই রকম দশ হাজার স্বাভাবিক সারির চেয়ে যত্ন করে বাছা দশটি রেকর্ড বেশি কিছু প্রকাশ করতে পারে।

DDL চালানোর আগে একটি ম্যাপিং ম্যাট্রিক্স তৈরি করুন। ম্যাট্রিক্সের প্রতিটি সারি একটি উৎস ধারণাকে প্রস্তাবিত গন্তব্য পর্যন্ত অনুসরণ করবে এবং প্রত্যাশিত সংখ্যা বা মান নথিবদ্ধ করবে। অর্ডার অ্যাপ্লিকেশনের ক্ষেত্রে নথিটি এমন হতে পারে:

পরিচিত তথ্যপ্রস্তাবিত গন্তব্যপ্রত্যাশিত ফল
অর্ডার A-তে দুটি লাইন আইটেম আছেorders এবং order_itemsএকটি অর্ডার সারি ও দুটি চাইল্ড সারি
অর্ডার B-তে কোনো নির্ধারিত অ্যাকাউন্ট নেইorders.account_idNULL অ্যাকাউন্টসহ একটি সারি
দুজন মানুষের একই ইমেইলcontacts.emailঅনন্যতা স্পষ্ট নিয়ম না হলে দুটি সারিই টিকে থাকে
পণ্যের কোডের শুরুতে শূন্য আছেproducts.codeটেক্সট মান 00417 অপরিবর্তিত থাকে
বাতিল অর্ডারে চার্জ থেকে যায়orders এবং chargesবাতিলের পরও চার্জ সারি থাকে

কনস্ট্রেইন্টের খুঁটিনাটি পর্যালোচনাকে বিভ্রান্ত করার আগে এটি টেবিল ম্যাপিংয়ের ভুল ধরে। AI বিল্ডাররা পুনরাবৃত্ত অবজেক্টকে আলাদা টেবিলে স্বাভাবিককরণ করে, যা সাধারণত যুক্তিসঙ্গত, কিন্তু পুনরাবৃত্তি একই পরিচয় প্রমাণ করে না। একই লেখা থাকা দুটি শিপিং ঠিকানা একটি সম্পাদনাযোগ্য ঠিকানা সারির রেফারেন্স না হয়ে ঐতিহাসিক স্ন্যাপশট হতে পারে। সেগুলো এক করলে পরে ঠিকানা সম্পাদনা ইতিহাস বদলে দেবে।

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

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

SELECT
    (SELECT count(*) FROM orders WHERE external_id = 'ORDER-A') AS order_a,
    (SELECT count(*) FROM order_items i
       JOIN orders o ON o.id = i.order_id
      WHERE o.external_id = 'ORDER-A') AS order_a_items,
    (SELECT account_id IS NULL FROM orders
      WHERE external_id = 'ORDER-B') AS order_b_unassigned;

পাস করা আউটপুটের রূপটি স্পষ্ট হওয়া উচিত:

 order_a | order_a_items | order_b_unassigned
---------+---------------+---------------------
       1 |             2 | t

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

কনস্ট্রেইন্টে ডোমেইনের সত্য থাকতে হবে

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

প্রাইমারি কি সারি শনাক্ত করে, কিন্তু নিজে থেকেই অর্থবহ ব্যবসায়িক পরিচয় দেয় না। একটি অভ্যন্তরীণ bigint ID, টেন্যান্টভিত্তিক অনন্য অর্ডার নম্বরের সঙ্গে থাকতে পারে। ব্যবসা যদি বলে অর্ডার নম্বর প্রতিটি টেন্যান্টে অনন্য, তাহলে UNIQUE (tenant_id, order_number) সেই নিয়ম প্রকাশ করে। গ্লোবাল ইউনিক কনস্ট্রেইন্ট বৈধ রেকর্ড প্রত্যাখ্যান করবে, আর কোনো কনস্ট্রেইন্ট না থাকলে পুনরায় চেষ্টার সময় অস্পষ্টতা থাকবে।

CHECK কনস্ট্রেইন্ট স্থিতিশীল সারি-তথ্যের জন্য উপযুক্ত, যেমন quantity > 0 বা finished_at >= started_at। PostgreSQL-এর ম্যানুয়াল বলে, ডেটাবেস ধরে নেয় CHECK এক্সপ্রেশন কনস্ট্রেইন্টের পুরো আয়ুতে অপরিবর্তনীয়। তাই কোনো ফাংশনের আচরণ পরে বদলে গেলে, সেই ফাংশন ডাকা CHECK পুরোনো সারিকে দৃশ্যমান নিয়ম ভঙ্গকারী অবস্থায় রেখে দিতে পারে। স্থির সত্যের জন্য স্থির এক্সপ্রেশন ব্যবহার করুন। পরিবর্তনশীল নীতি, যেমন অ্যাডমিনরা নিয়ন্ত্রণ করা বর্তমানে অনুমোদিত সেট, রেফারেন্স করা টেবিল বা অ্যাপ্লিকেশন ওয়ার্কফ্লোতে রাখুন।

তৈরি হওয়া স্ট্যাটাস কনস্ট্রেইন্ট সন্দেহের চোখে দেখুন। বিল্ডার বর্তমান উদাহরণ দেখে এমন তৈরি করতে পারে:

status text NOT NULL
    CHECK (status IN ('draft', 'active', 'closed'))

এটি কেবল তখনই ঠিক, যখন এগুলো সম্পূর্ণ ও স্থায়ী সব অবস্থা। ব্যর্থ, বাতিল, স্থগিত, আমদানি করা এবং অজানা পুরোনো রেকর্ডের কথা জিজ্ঞেস করুন। স্টেট মেশিন এখনও বদলালে লুকআপ টেবিল নতুন অবস্থা যোগ করা স্পষ্ট করতে পারে, কিন্তু এটি ট্রানজিশন যাচাইয়ের বিকল্প নয়। কোনো সারিতে closed থাকা বৈধ মানে এই নয় যে সেটি সরাসরি draft থেকে closed-এ যেতে পারে।

অনন্যতা ভেবে ব্যবহার করুন। PostgreSQL ইউনিক কনস্ট্রেইন্ট একটি ইউনিক B-tree ইনডেক্স দিয়ে বাস্তবায়ন করে, কিন্তু আংশিক ইউনিক ইনডেক্স ভিন্ন নিয়ম প্রকাশ করে। সফট ডিলিশনে প্রায়ই শুধু সক্রিয় সারির মধ্যে অনন্যতা দরকার হয়:

CREATE UNIQUE INDEX users_tenant_email_live_uq
    ON users (tenant_id, lower(email))
    WHERE deleted_at IS NULL;

এটি UNIQUE (tenant_id, email, deleted_at)-এর সমতুল্য নয়। PostgreSQL তার অনন্যতার নিয়ম অনুযায়ী NULL মানকে বিবেচনা করে, আর ডিলিশনের টাইমস্ট্যাম্প যোগ করলে যে পরিচয় বলবৎ হচ্ছে তা বদলে যায়। কলামের তালিকা দেখে আচরণ অনুমান না করে ফিক্সচারে সঠিক ডুপ্লিকেট কেস পর্যালোচনা করুন।

নালযোগ্যতা একটি ব্যবসায়িক সিদ্ধান্ত

কোনো কলামে NOT NULL দিন শুধু তখনই, যখন ডোমেইনে প্রতিটি বৈধ সারির জন্য মান দরকার এবং প্রতিটি লেখার পথ সেই মান দিতে পারে। স্ক্রিনের ডিজাইন দুর্বল প্রমাণ। বর্তমান ফর্মে ফিল্ড বাধ্যতামূলক হলেই ইমপোর্ট, খসড়া, সিস্টেমে তৈরি সারি বা ঐতিহাসিক রেকর্ড সম্পর্কে কিছু বলা যায় না।

চারটি অবস্থা আলাদাভাবে দেখুন: উৎস ফিল্ডটি দেয়নি, উৎস স্পষ্টভাবে null পাঠিয়েছে, উৎস খালি মান পাঠিয়েছে, এবং উৎস অর্থপূর্ণ মান দিয়েছে। JSON API, ফর্ম, CSV ইমপোর্ট ও PostgreSQL এসব অবস্থা ভিন্নভাবে সামলাতে পারে। অ্যাপ্লিকেশন যদি ইনসার্টের আগে চারটিকেই এক করে ফেলে, তাহলে ডেটাবেস তা সমাধান করেছে এমন ভান না করে স্কিমা পর্যালোচনায় সিদ্ধান্তটি প্রকাশ করা উচিত।

ডিফল্টও একই মনোযোগ চায়। INSERT কলাম বাদ দিলে ডিফল্ট মান দেয়, স্পষ্ট NULL ঠিক করে না, আর মানটি সত্য প্রমাণও করে না। অজানা দেশ সম্ভব হলে country_code DEFAULT 'US' বিপজ্জনক। তখন সারিতে আত্মবিশ্বাসী একটি মিথ্যা থাকে, যেটি রিপোর্ট ও কমপ্লায়েন্স লজিক বিশ্বাস করতে পারে।

সাধারণ একটি তৈরি হওয়া মাইগ্রেশন এক স্টেটমেন্টে বাধ্যতামূলক কলাম যোগ করে:

ALTER TABLE customers
    ADD COLUMN account_type text NOT NULL DEFAULT 'standard';

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

কিছু কনস্ট্রেইন্টের জন্য PostgreSQL উপকারী একটি বিভাজন দেয়। CHECK বা ফোরেন কি NOT VALID হিসেবে যোগ করা যায়, এতে তৈরির সময় পুরোনো সব সারি যাচাই হয় না, পরে VALIDATE CONSTRAINT দিয়ে পরীক্ষা করা যায়। ম্যানুয়াল একে প্রাথমিক টেবিল স্ক্যান পিছিয়ে দেওয়ার উপায় হিসেবে নথিবদ্ধ করেছে। পুরোনো লঙ্ঘন উপেক্ষার অনুমতি এটি নয়: নতুন লেখায় নিয়ম বলবৎ হয়, আর অনুমোদনের আগে যাচাই ধাপেও পাস করতে হবে।

নালযোগ্যতা কঠোর করার আগে এমন ডিস্ট্রিবিউশন কুয়েরি চালান যা আসল শ্রেণিগুলো দেখায়:

SELECT
    count(*) AS total,
    count(*) FILTER (WHERE account_type IS NULL) AS nulls,
    count(*) FILTER (WHERE account_type = '') AS empty_strings,
    count(*) FILTER (WHERE account_type NOT IN
        ('standard', 'partner', 'internal')) AS unexpected
FROM customers;

AI-তৈরি ডিফল্ট মাইগ্রেশনের পর এই কুয়েরিকে পরিষ্কার দেখাতে পারে। ব্যাকফিলের আগেও এটি চালান এবং ফল সংরক্ষণ করুন। নইলে কোন মান তৈরি করা আর কোনটি বানানো, তা আলাদা করার প্রয়োজনীয় প্রমাণ হারাবেন।

ইনডেক্স বাস্তবে দেখা অ্যাক্সেস প্যাটার্নের উত্তর দেবে

পুনরুদ্ধারের পথ মহড়া দিন
তৈরি হওয়া অ্যাপ্লিকেশনের জন্য পরীক্ষিত পুনরুদ্ধার প্রক্রিয়ার অংশ হিসেবে স্ন্যাপশট ও রোলব্যাক ব্যবহার করুন।

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

তৈরি হওয়া অ্যাপ্লিকেশন যে কুয়েরিগুলো সত্যিই পাঠায় সেগুলো দিয়ে শুরু করুন। ফিল্টার কলাম, টেন্যান্ট সীমা, জয়ন কলাম, সাজানোর ধরন ও প্রত্যাশিত ফলের আকার লিখে রাখুন। সাম্প্রতিক অর্ডারের পেজে টেবিল ডায়াগ্রামের চেয়ে এই কুয়েরির ধরন বেশি গুরুত্বপূর্ণ:

SELECT id, order_number, status, created_at
FROM orders
WHERE tenant_id = $1
  AND status = $2
ORDER BY created_at DESC
LIMIT 50;

শুধু tenant_id-এর ইনডেক্সে এখনও অনেক টেন্যান্ট সারি দেখতে ও সাজাতে হতে পারে। (tenant_id, status, created_at DESC) ইনডেক্সটি এই অ্যাক্সেস প্যাটার্নের সঙ্গে বেশি মেলে। কলামের ক্রম জনপ্রিয়তার প্রতিযোগিতা নয়; এটি বাস্তব কুয়েরিতে সমতার শর্ত, রেঞ্জ শর্ত, সাজানো ও নির্বাচনী ক্ষমতা অনুসরণ করে।

প্রতিনিধিত্বমূলক ডেটার ওপর EXPLAIN (ANALYZE, BUFFERS) চালান, কিন্তু ছোট একটি ফিক্সচারকে পারফরম্যান্সের প্রমাণ ভাববেন না। ছোট টেবিলে PostgreSQL ঠিকভাবেই সিকোয়েন্সিয়াল স্ক্যান পছন্দ করতে পারে। যাচাইয়ে নিশ্চিত করতে হবে যে কাঙ্ক্ষিত ইনডেক্স আছে এবং উৎপাদনের মতো আকারের মহড়া প্ল্যানারকে বাস্তবসম্মত পছন্দ দেয়। অনুমোদনের জন্য জোর করে ইনডেক্স স্ক্যান দেখাতে কখনও সিকোয়েন্সিয়াল স্ক্যান বন্ধ করবেন না।

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

শুরুর প্রস্তাবে ডুপ্লিকেট ও অব্যবহৃত ইনডেক্স প্রত্যাখ্যান করুন। উপযুক্ত (tenant_id, status, created_at) ইনডেক্স থাকলে (tenant_id, status) অপ্রয়োজনীয় হতে পারে, যদিও কাজের চাপের খুঁটিনাটি সিদ্ধান্ত বদলাতে পারে। নাম নয়, সংজ্ঞা তুলনা করুন। AI বিল্ডাররা প্রায়ই প্রতিটি ফিচারের জন্য একটি ইনডেক্স তৈরি করে এবং খেয়াল করে না যে কয়েকটি ফিচার একই শুরুর কলাম চেয়েছে।

বিদ্যমান ব্যস্ত ডেটাবেসে মনে রাখুন, CREATE INDEX CONCURRENTLY ট্রানজ্যাকশন ব্লকের ভেতরে চলতে পারে না, বেশি কাজ করে এবং ব্যর্থতার পর অবৈধ ইনডেক্স রেখে যেতে পারে। PostgreSQL-এর ম্যানুয়াল এই পরিচালনাগত পার্থক্যগুলো স্পষ্ট করেছে। প্রতিটি মাইগ্রেশন ট্রানজ্যাকশনে মোড়ানো মাইগ্রেশন ফ্রেমওয়ার্কে আশাবাদী কীওয়ার্ড বদলের বদলে স্পষ্ট ব্যতিক্রম ও পরিষ্কারের প্রক্রিয়া দরকার।

ফোরেন কির জন্য মালিকানা ও ডিলিশন নিয়ম দরকার

দল সম্পর্কটি মালিকানা, রেফারেন্স, ঐচ্ছিক প্রসঙ্গ নাকি ঐতিহাসিক সম্পৃক্ততা বোঝায় তা ঠিক করার পরই ফোরেন কি সঠিক হয়। দেখতে একই রকম কলামে বিপরীত ডিলিশন আচরণ দরকার হতে পারে।

projects.owner_user_id, invoices.customer_id এবং audit_events.actor_user_id বিবেচনা করুন। একটি প্রজেক্টের মালিকানা বদলাতে পারে। কাস্টমার অ্যাকাউন্ট বন্ধ হলেও ইনভয়েস টিকে থাকতে হতে পারে। পরিচয়ের তথ্য মুছে ফেলার পরও অডিট ইভেন্টে অভিনেতার পুরোনো পরিচায়ক রাখা লাগতে পারে। তিনটিই users রেফারেন্স করে বলে সবকটিতে ON DELETE CASCADE দেওয়া ধ্বংসাত্মক কল্পনাকে নিয়মে পরিণত করবে।

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

SET NULL-ও অর্থগত পর্যালোচনা চায়। এটি চাইল্ড সারি রাখে, কিন্তু সরাসরি সম্পর্ক মুছে দেয়। পরে কর্মীদের যদি ব্যাখ্যা করতে হয় কোন অ্যাকাউন্ট একটি রিপোর্ট তৈরি করেছে, নাল রেফারেন্স যথেষ্ট নাও হতে পারে। পরিচয় প্রকাশ না করা ঐতিহাসিক টোকেন বা স্ন্যাপশট রাখলে সব ব্যক্তিগত তথ্য না রেখেও জবাবদিহি রাখা যায়, তবে নির্দিষ্ট সংরক্ষণ সিদ্ধান্ত পণ্যের নীতির বিষয়, AI-এর অনুমান নয়।

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

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

মহড়ার ডেটাবেসে মাইগ্রেশন প্রয়োগের পর ক্যাটালগ পরীক্ষা করুন:

SELECT
    conname,
    contype,
    convalidated,
    pg_get_constraintdef(oid) AS definition
FROM pg_constraint
WHERE conrelid = 'public.orders'::regclass
ORDER BY conname;

প্রতিনিধিত্বমূলক আউটপুট এমন হয়:

       conname        | contype | convalidated | definition
----------------------+---------+--------------+---------------------------------------
 orders_pkey          | p       | t            | PRIMARY KEY (id)
 orders_customer_fk   | f       | t            | FOREIGN KEY (customer_id) REFERENCES customers(id)
 orders_total_check   | c       | t            | CHECK ((total_cents >= 0))

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

যুক্তিসঙ্গত SQL-এর মধ্যেও ধ্বংসাত্মক পরিবর্তন লুকিয়ে থাকে

পর্যালোচিত নিয়ম থেকে তৈরি করুন
অনুমোদিত ডোমেইন নিয়মগুলো চ্যাটের মাধ্যমে ওয়েব, সার্ভার বা মোবাইল অ্যাপ্লিকেশনে রূপ দিন।

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

চূড়ান্ত স্কিমা একই দেখালেও রিনেম আর ড্রপ পরিচালনাগতভাবে আলাদা। surname যদি family_name হয়, রিনেম ডেটা ও নির্ভরতা বেশি বিশ্বস্তভাবে রাখে। পুরোনো কলাম ড্রপ করে নতুনটি যোগ করলে ডায়াগ্রাম একই হয়, কিন্তু সব মান খালি হয়ে যায়। তৈরি হওয়া মাইগ্রেশন প্রায়ই ধারাবাহিকতা না বুঝে শেষ অবস্থা অনুমান করে।

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

এই কাজগুলোর জন্য লিখিত যুক্তি চাই: টেবিল বা কলাম ড্রপ করা, ক্ষতিকর কাস্টে টাইপ বদলানো, পূর্ণ কলাম প্রতিস্থাপন, CASCADE যোগ করা, তৈরি হওয়া ব্যাকফিলের পর NOT NULL দেওয়া এবং ভিন্ন কলাম দিয়ে অনন্যতা পুনর্গঠন। তৈরি হওয়া ফাংশন বা মাইগ্রেশন কলব্যাকে থাকা কাঁচা SQL-ও পরীক্ষা করুন। টেক্সট সার্চ শুরু করার ফিল্টার, পুরো পর্যালোচনা নয়।

একটি ব্যর্থতার ধরন বারবার দেখা যায়। পরিচিত ডেটায় ঐচ্ছিক কোম্পানিসহ কনট্যাক্ট আছে, কিন্তু নমুনা স্ক্রিনে কেবল ব্যবসায়িক কনট্যাক্ট দেখা যায়। বিল্ডার contacts.company_id-কে NOT NULL করে এবং অমিল সারির জন্য Unknown নামে তৈরি কোম্পানি ইনসার্ট করে। মাইগ্রেশন পাস করে, সংখ্যা মিলে যায়, প্রতিটি ফোরেন কি যাচাই হয়। তবু ডেটা ভুল: ব্যক্তিগত কনট্যাক্ট এখন কোনো কোম্পানির বলে দেখা যায়, রিপোর্টে সম্পর্কহীন মানুষ একসঙ্গে গ্রুপ হয়, আর প্লেসহোল্ডার মুছলে আসল কনট্যাক্টেও ক্যাসকেড হতে পারে।

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

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

মহড়ায় ফল ও ব্যর্থতার আচরণ প্রমাণ করতে হবে

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

এই মহড়ার ক্রমটি রিলিজ নথি হিসেবে ব্যবহার করুন:

  1. পরিবর্তনের আগের ডেটাসেট একটি বিচ্ছিন্ন ডেটাবেসে রিস্টোর করুন এবং সারি সংখ্যা ও অর্থগত অ্যাসারশন নথিবদ্ধ করুন。
  2. বর্তমান স্কিমা ধারণ করুন, হুবহু মাইগ্রেশন আর্টিফ্যাক্ট প্রয়োগ করুন এবং সময় ও ট্রানজ্যাকশন সীমাসহ সব আউটপুট সংরক্ষণ করুন。
  3. ক্যাটালগ পরীক্ষা, ম্যাপিং অ্যাসারশন, কনস্ট্রেইন্ট প্রত্যাখ্যান পরীক্ষা এবং প্রতিনিধিত্বমূলক অ্যাপ্লিকেশন কুয়েরি চালান。
  4. অমিল ও নাল শ্রেণিসহ গুরুত্বপূর্ণ মান রেকর্ড করা প্রত্যাশার সঙ্গে তুলনা করুন。
  5. নথিবদ্ধ পুনরুদ্ধার পদ্ধতি অনুশীলন করুন, তারপর পুনরুদ্ধার করা ডেটাবেসে মাইগ্রেশনের আগের অ্যাসারশন আবার চালান。

আগে ও পরে শুধু স্কিমার ডাম্প নিন:

pg_dump --schema-only --no-owner --no-privileges \
  --dbname "$DATABASE_URL" > schema.sql

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

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

BEGIN;

INSERT INTO order_items (order_id, quantity, unit_price_cents)
VALUES (1001, 0, 2500);

ROLLBACK;

প্রত্যাশিত আউটপুটে ভাঙা কনস্ট্রেইন্টের নাম থাকা উচিত, যেমন:

ERROR:  new row for relation "order_items" violates check constraint "order_items_quantity_check"
DETAIL:  Failing row contains (..., 0, 2500, ...).

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

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

পুনরুদ্ধারে উল্টো মাইগ্রেশনের চেয়ে বেশি কিছু লাগে

ডোমেইনের অর্থ থেকে তৈরি করুন
আপনার পর্যালোচকেরা যে ডোমেইন ভাষায় একমত হয়েছেন, সেই ভাষাকে ঘিরে অ্যাপ্লিকেশন তৈরি করুন।

পুনরুদ্ধার বিশ্বাসযোগ্য তখনই, যখন পরিষেবা যতক্ষণ বন্ধ রাখা যায় সেই সময়ের মধ্যে এটি ডেটা ও অ্যাপ্লিকেশনের সামঞ্জস্য ফিরিয়ে দেয়। বাদ দেওয়া কলাম আবার তৈরি করা উল্টো মাইগ্রেশন তাদের পুরোনো মান ফিরিয়ে আনে না।

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

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

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

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

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

পুরোনো ডেটাবেস রিস্টোর করার পর কোন বিন্দুতে পুরোনো অ্যাপ্লিকেশনও রিস্টোর করা লাগবে তা নথিবদ্ধ করুন। নতুন অ্যাপ্লিকেশন নতুন কলামের ওপর নির্ভর করতে পারে, আর পুরোনো অ্যাপ্লিকেশন নতুন enum মান প্রত্যাখ্যান করতে পারে বা পুরোনো আকৃতি লিখতে পারে। ডেটাবেস ও অ্যাপ্লিকেশন পুনরুদ্ধারে সামঞ্জস্যপূর্ণ সংস্করণ ব্যবহার করতে হবে।

অনুমোদনে আত্মবিশ্বাস নয়, প্রমাণ লাগে

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

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

Koder.ai-তে কোনো অ্যাপ্লিকেশন তৈরি করার সময়, মাইগ্রেশন অনুমতি দেওয়ার আগে পরিকল্পনা মোডে এই স্কিমা সিদ্ধান্তগুলো লিখে রাখুন, পর্যালোচনার জন্য সোর্স এক্সপোর্ট করুন এবং পরিচিত ডেটাসেটের বিপরীতে মহড়া প্রয়োজন এমন পুনরুদ্ধার টুল হিসেবে স্ন্যাপশট ও রোলব্যাককে দেখুন।

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

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

সাধারণ প্রশ্ন

AI দিয়ে তৈরি PostgreSQL স্কিমায় কী কী পরীক্ষা করা উচিত?

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

স্কিমা যাচাইয়ের ডেটাসেট কত বড় হওয়া উচিত?

এমন একটি ছোট ডেটাসেট নিন যাতে সাধারণ রেকর্ড, সীমার মান, অনুপস্থিত সম্পর্ক, ডুপ্লিকেট, নাল, খালি স্ট্রিং এবং পুরোনো অস্বাভাবিক তথ্য থাকে। এর উদ্দেশ্য বেশি ডেটা রাখা নয়, উৎপাদনের ডেটা তার আগে বিল্ডারের অনুমান ভুল প্রমাণ করা।

সফল পরীক্ষামূলক মাইগ্রেশন কি প্রমাণ করে যে স্কিমা নিরাপদ?

না। সফল মাইগ্রেশন শুধু প্রমাণ করে যে সেই ডেটাবেস অবস্থায় PostgreSQL স্টেটমেন্টগুলো গ্রহণ করেছে। এটি প্রমাণ করে না যে টেবিল ম্যাপিং ঠিক, ডেটা তার অর্থ ধরে রেখেছে, ইনডেক্স বাস্তব কুয়েরির জন্য যথেষ্ট, বা পুনরুদ্ধার কাজ করে।

PostgreSQL কলাম কখন NOT NULL হওয়া উচিত?

কোনো ফিল্ডে NOT NULL দিন কেবল তখনই, যখন প্রতিটি বৈধ রেকর্ডে তার মান থাকে এবং অ্যাপ্লিকেশন প্রতিটি লেখার পথে সেই মান দিতে পারে। শুধু কনস্ট্রেইন্ট পূরণ করতে বানানো ডিফল্ট ব্যবহার করবেন না, কারণ তাতে দৃশ্যমান অনুপস্থিত তথ্য বিশ্বাসযোগ্য কিন্তু ভুল তথ্যে বদলে যায়।

ইউনিক কনস্ট্রেইন্ট ব্যবহার করব, নাকি ইউনিক ইনডেক্স?

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

PostgreSQL ফোরেন কি কি স্বয়ংক্রিয়ভাবে ইনডেক্স তৈরি করে?

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

ON DELETE CASCADE কখন নিরাপদ?

CASCADE ব্যবহার করুন কেবল তখনই, যখন প্যারেন্ট মুছে গেলে চাইল্ড সারির আর স্বাধীন কোনো অর্থ থাকে না। মুছে ফেলা যদি ব্যবসায়িক সিদ্ধান্ত হয় অথবা চাইল্ডটি ইনভয়েস বা অডিট রেকর্ডের মতো প্রমাণ হয়, তাহলে মুছে ফেলা প্রত্যাখ্যান করুন বা স্পষ্ট প্রক্রিয়ায় সামলান।

মাইগ্রেশনে ধ্বংসাত্মক পরিবর্তন কীভাবে শনাক্ত করব?

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

মাইগ্রেশন পুনরুদ্ধার পরীক্ষা করার সবচেয়ে নিরাপদ উপায় কী?

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

স্কিমা অনুমোদনের পর কোন প্রমাণগুলো সংরক্ষণ করা উচিত?

তৈরি হওয়া DDL, মাইগ্রেশনের লেখা, স্কিমা ডিফ, যাচাইয়ের কুয়েরি ও ফল, পুনরুদ্ধার প্রক্রিয়া এবং পর্যালোচকের পরিচয় একসঙ্গে রাখুন। এই নথি বলে দেয় কী অনুমোদিত হয়েছিল এবং পরের মাইগ্রেশন পর্যালোচনায় বদলে যাওয়া অনুমান শনাক্ত করতে সাহায্য করে।

Related posts