এই পর্বে যা শিখবেন
- DBMS-এর লিখিত উত্তর পরীক্ষকের মার্ক-স্কিমের ক্রমে সাজানো, আর প্রতিটি ধরনের প্রশ্নে কোথায় নম্বর আসে
- ক্লাসিক দীর্ঘ প্রশ্ন — ER থেকে টেবিল, SQL লেখা, relational algebra, candidate key, canonical cover, 3NF ও BCNF decomposition — নির্ভুল ধাপে সমাধান
- B+ tree insert, external sort আর join-এর খরচ, precedence graph, 2PL, deadlock আর log-ভিত্তিক recovery হাতে করে বের করা
- ভাইভায় এক–তিন বাক্যে নির্ভুল উত্তর, জোরে ভেবে বলা, টেবিল এঁকে দেখানো আর না জানলে সৎ থাকা
- AI-এর দেওয়া SQL, normalization আর schedule-এর উত্তর চালিয়ে ও হিসাব করে যাচাই করা
১ · পরীক্ষক কী খোঁজেন — DBMS উত্তরের কাঠামো আর মার্ক-স্কিম
MCQ-তে উত্তর হয় ঠিক, নয় ভুল। লিখিত পরীক্ষা আর ভাইভা আলাদা: দুজন প্রার্থী একই normalization জানেন, কিন্তু একজন বেশি নম্বর পান — কারণ তিনি সংজ্ঞা নির্ভুল লিখেছেন, ছোট একটি টেবিলে সমস্যাটি দেখিয়েছেন, ধাপে ধাপে decomposition করেছেন আর শেষে যাচাই করেছেন যে কিছু হারায়নি। খাতা দেখার সময় পরীক্ষকের হাতে থাকে একটি মার্ক-স্কিম: কোন অংশে কত নম্বর। আপনার কাজ সেই তালিকার প্রতিটি ঘর খাতায় সহজে খুঁজে পেতে দেওয়া।
পাঁচ অংশের কাঠামো
মুদি দোকানের নতুন কর্মচারীকে খাতা রাখার নিয়ম বোঝানোর মতো: নিয়মটি এক বাক্যে, কেন এই নিয়ম, খাতার একটি পাতা দেখিয়ে, একটি ছোট নকশা, আর কখন নিয়মটি ঝামেলা বাড়ায়। ছোট প্রশ্নে প্রথম তিনটি অংশই যথেষ্ট; দশ নম্বরের প্রশ্নে একটি অংশ বাদ পড়লে একটি নম্বর-ভাগ ফাঁকা থাকে। নিচের মডেল উত্তরগুলো এই ক্রম মেনেছে।
প্রশ্নের ধরন অনুযায়ী মার্ক-স্কিম
| ধরন | যাতে নম্বর আসে | যাতে নম্বর কাটে |
|---|---|---|
| সংজ্ঞা ও পার্থক্য | নির্ভুল এক–দুই বাক্য, একটি ছোট টেবিলের উদাহরণ; পার্থক্যে একই মাপকাঠির সারি (কাজ, গতি, NULL, rollback, ব্যবহার) | উদাহরণ ছাড়া মুখস্থ বাক্য; দুই কলামে আলাদা মাপকাঠি |
| ER আঁকুন ও টেবিলে রূপান্তর | প্রতিটি entity-র key, relationship-এর cardinality আর participation, weak entity-র partial key; mapping-এ প্রতিটি টেবিলের PK আর FK | M:N-কে আলাদা টেবিল না বানানো; FK ভুল দিকে; cardinality না লেখা |
| SQL লিখুন | ঠিক JOIN শর্ত, NULL আর ডুপ্লিকেট ভাবা, GROUP BY-তে সব non-aggregate কলাম, প্রয়োজনে LEFT JOIN; ফলের দুই–তিনটি সারি দেখানো | শুধু “চলে” এমন কোয়েরি, যার ফল ভুল; ভুয়া কলামের নাম; NOT IN-এ NULL ভুলে যাওয়া |
| Relational algebra | ভেতর থেকে বাইরে সাজানো expression, প্রতিটি join-এর শর্ত, শেষে π; চাইলে expression tree | natural join-এ একই নামের কলাম নীরবে মিলে যাওয়া খেয়াল না করা |
| FD, key, normal form | প্রতিটি closure-এর হিসাব লেখা, সব candidate key, কোন FD কোন নিয়ম ভাঙে, decomposition-এর পর lossless আর dependency preservation দুটিই যাচাই | শুধু চূড়ান্ত টেবিল; একটি candidate key বাদ; “BCNF সবসময় dependency রাখে” ধরনের ভুল দাবি |
| Trace ও খরচ | প্রতিটি ধাপের অবস্থা (B+ tree-এর node, run-এর সংখ্যা, lock table), সূত্র, সংখ্যা বসানো, চূড়ান্ত উত্তর আলাদা করে | একক না বলা (page I/O না সারি), ceiling ভুলে যাওয়া, মাঝের ধাপ বাদ |
| Transaction ও recovery | schedule-এর প্রতিটি conflict জোড়া, graph, সিদ্ধান্ত; log-এ redo আর undo তালিকা, চূড়ান্ত মান | R-R জোড়াকে conflict ধরা; checkpoint-এর আগের commit-কে redo করা বা না-করা নিয়ে যুক্তি না দেওয়া |
সময়ের হিসাব: তিন ঘণ্টায় ১০০ নম্বর হলে প্রতি নম্বরে মোটামুটি দুই মিনিট — ১০ নম্বরের প্রশ্নে ২০ মিনিটের বেশি নয়। আটকে গেলে যতটুকু পেরেছেন (key, কোন FD নিয়ম ভাঙে) গুছিয়ে লিখে এগিয়ে যান; পদ্ধতির কাঠামোতেও আংশিক নম্বর আসে। প্রশ্নগুলো মডিউল অনুযায়ী সাজানো; বারবার আটকালে অংশের শুরুর পর্বগুলো আবার পড়ুন:
| কোর্সের মডিউল | পর্ব | লিখিত প্রশ্ন | ভাইভা প্রশ্ন |
|---|---|---|---|
| ১–২ · ভিত্তি ও ডেটাবেস ডিজাইন | ০১–১১ | অংশ ২ (ক-০১–ক-০৮) | ভ-০১–ভ-১০ |
| ৩–৪ · SQL-এর ভিত্তি ও উন্নত SQL | ১২–৩১ | অংশ ৩ (খ-০১–খ-১০) | ভ-১১–ভ-২০ |
| ৫ · Relational algebra ও normalization | ৩২–৩৮ | অংশ ৪ (গ-০১–গ-০৭) | ভ-২১–ভ-২৫ |
| ৬ · স্টোরেজ, index ও query processing | ৩৯–৪৩ | অংশ ৫ (ঘ-০১–ঘ-০৫) | ভ-২৬–ভ-৩০ |
| ৭ · Transaction ও concurrency | ৪৪–৪৮ | অংশ ৬ (ঙ-০১–ঙ-০৬) | ভ-৩১–ভ-৩৫ |
| ৮–৯ · অ্যাপ, নিরাপত্তা, NoSQL ও বড় মাপ | ৪৯–৬২ | অংশ ৭ (চ-০১–চ-০৬) | ভ-৩৬–ভ-৪২ |
এই পাতার কোনো প্রশ্ন কোনো নির্দিষ্ট পরীক্ষার প্রশ্নপত্র বা প্রতিষ্ঠানের ইন্টারভিউ থেকে নেওয়া নয়; এগুলো এমন ধরনের প্রশ্ন, যা বিশ্ববিদ্যালয়, চাকরি বা ইন্টারভিউর পরীক্ষায় প্রায়ই আসে। প্রশ্নের পাশের নম্বর শুধু আনুমানিক ওজন। লাইভ এডিটর চলে SQLite-এ; PostgreSQL, MySQL বা অন্য DBMS যেখানে আলাদা, তা বলা আছে।
২ · অংশ ক — ডেটাবেসের ভিত্তি আর ডিজাইন (মডিউল ১–২)
রিভিশনের জন্য: পর্ব ০১, পর্ব ০২, পর্ব ০৩, পর্ব ০৪, পর্ব ০৫, পর্ব ০৬, পর্ব ০৭, পর্ব ০৮, পর্ব ০৯, পর্ব ১০, পর্ব ১১.
এই অংশের প্রশ্ন দুই রকম: সংজ্ঞা-ব্যাখ্যার দীর্ঘ উত্তর (DBMS-এর সুবিধা, three-schema, key) আর ডিজাইনের সমস্যা (একটি পরিস্থিতি পড়ে ER আঁকা, তারপর টেবিলে রূপান্তর)। দ্বিতীয়টিতে নম্বর বেশি, আর ভুলও বেশি হয়।
ক-০১File processing system-এর তুলনায় DBMS-এর সুবিধাগুলো উদাহরণসহ ব্যাখ্যা করুন। DBMS-এর অসুবিধা কী? — ১০ নম্বর (মাঝারি)
সংজ্ঞা: DBMS (Database Management System) হলো এমন সফটওয়্যার, যা পরস্পর-সম্পর্কিত ডেটা একটি কেন্দ্রীয় ডেটাবেসে রাখে, আর সেই ডেটা সংজ্ঞায়িত করা, খোঁজা, বদলানো, একসাথে বহুজনের ব্যবহার, নিরাপত্তা আর ব্যর্থতার পর উদ্ধারের কাজ নিজে সামলায়। File processing system-এ প্রতিটি অ্যাপ নিজের ফাইল রাখে আর নিজের কোডে পড়ে-লেখে।
ব্যাখ্যা ও উদাহরণ: ধরুন বিশ্ববিদ্যালয়ের ভর্তি শাখা, হিসাব শাখা আর লাইব্রেরি আলাদা ফাইলে শিক্ষার্থীর নাম-ঠিকানা রাখে। DBMS যে সমস্যাগুলো মেটায়:
- Redundancy আর inconsistency: ঠিকানা তিন ফাইলে থাকলে একটিতে বদলালে বাকি দুটি পুরোনো থাকে (data inconsistency). DBMS-এ ঠিকানা একবার; বাকিরা student_id দিয়ে যুক্ত।
- সহজ খোঁজ: নতুন প্রশ্নের জন্য নতুন প্রোগ্রাম নয়, একটি SQL কোয়েরি।
- Integrity constraint: “CGPA ০ থেকে ৪”, “বিভাগ আগে থাকতে হবে” — স্কিমায় একবার (CHECK, FOREIGN KEY), প্রতিটি অ্যাপের কোডে নয়।
- Atomicity: bKash-এ টাকা পাঠানোর মাঝপথে বিদ্যুৎ গেলে হয় দুটি বদলই, নয় কোনোটিই।
- Concurrent access: দুজন একসাথে ট্রেনের শেষ টিকিট কিনলে lost update — DBMS lock বা MVCC দিয়ে ঠেকায়।
- নিরাপত্তা, backup-recovery আর data independence: কলাম-স্তরের অনুমতি (GRANT, view), log থেকে উদ্ধার, আর ফাইলের গঠন বদলালেও অ্যাপ অপরিবর্তিত (ক-০২)।
অসুবিধা: সফটওয়্যার, হার্ডওয়্যার আর দক্ষ লোকের খরচ; ছোট এক-ব্যবহারকারীর কাজে অকারণ ভার; কেন্দ্রীয় হওয়ায় একটি ব্যর্থতা সবাইকে থামায় (তাই replication); কিছু কাজে (বিশাল লগ, ভিডিও) সাধারণ ফাইলই দ্রুত।
নম্বর কোথায়: সংজ্ঞা (১), অন্তত ছয়টি সুবিধা, প্রতিটির সাথে একটি বাস্তব উদাহরণ (৬–৭), অসুবিধা (১–২)। “redundancy কমে” লিখে কেন কমে তা না বললে অর্ধেক নম্বর। পর্ব ০২
ক-০২Three-schema architecture ছবি এঁকে ব্যাখ্যা করুন। Logical আর physical data independence কী? কোনটি অর্জন করা কঠিন, কেন? — ৮ নম্বর (মাঝারি)
সংজ্ঞা: Three-schema architecture (ANSI/SPARC প্রস্তাব) ডেটাবেসের বর্ণনাকে তিন স্তরে ভাগ করে, যাতে এক স্তরের বদল অন্য স্তরকে না ছোঁয়।
ব্যবহারকারী ১ ব্যবহারকারী ২ ব্যবহারকারী ৩
┌───────────┐ ┌───────────┐ ┌───────────┐
│ external │ │ external │ │ external │ view: যে যা দেখে
│ schema 1 │ │ schema 2 │ │ schema 3 │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
└──── external/conceptual mapping ──┘
┌───────────────┐
│ conceptual │ সব টেবিল, কলাম,
│ schema │ সম্পর্ক, constraint
└───────┬───────┘
conceptual/internal mapping
┌───────────────┐
│ internal │ file, page, index,
│ schema │ B+ tree, compression
└───────────────┘
ব্যাখ্যা: External স্তরে প্রতিটি ব্যবহারকারী-দলের নিজের দৃশ্য — হিসাব শাখা দেখে নাম আর বকেয়া, লাইব্রেরি দেখে নাম আর ধার করা বই। Conceptual স্তরে পুরো ডেটাবেসের যৌক্তিক গঠন: টেবিল, কলাম, key, constraint. Internal স্তরে ডিস্কে কীভাবে রাখা: file, index, সারির ক্রম। দুটি mapping এক স্তরের অনুরোধ পরের স্তরে অনুবাদ করে।
Data independence: নিচের স্তরের স্কিমা বদলালেও ওপরের স্তর না বদলানোর ক্ষমতা। Physical: internal স্কিমা বদলালেও (নতুন index, অন্য ডিস্ক, partition) conceptual স্কিমা আর অ্যাপ অপরিবর্তিত — শুধু conceptual/internal mapping বদলায়। Logical: conceptual স্কিমা বদলালেও (নতুন কলাম, একটি টেবিল দুই ভাগ) external স্কিমা আর অ্যাপ অপরিবর্তিত — view দিয়ে পুরোনো রূপ ধরে রাখা যায়।
কোনটি কঠিন: logical. কারণ অ্যাপগুলো সরাসরি টেবিল আর কলামের নাম ধরে লেখা; একটি কলাম মুছলে বা টেবিল ভাঙলে প্রতিটি view আর কোয়েরি নতুন গঠনে মেলানো যায় কি না, তা নিশ্চিত নয় (যেমন join-এর ওপর গড়া view-তে UPDATE সবসময় চলে না)। physical বদল SQL-এর কাছে অদৃশ্য — CREATE INDEX দিলে কোনো কোয়েরির ফল বদলায় না, শুধু গতি।
নম্বর কোথায়: তিন স্তরের নামসহ ছবি (২), প্রতিটি স্তরের এক লাইনের কাজ আর উদাহরণ (৩), দুই ধরনের independence-এর সংজ্ঞা ও উদাহরণ (২), কোনটি কঠিন আর কেন (১)। পর্ব ০৩
ক-০৩Relation, tuple, attribute, domain, degree আর cardinality সংজ্ঞায়িত করুন। একটি relation-এর বৈশিষ্ট্যগুলো কী? — ৫ নম্বর (সহজ)
সংজ্ঞা ও উদাহরণ: db-uni-এর departments(dept_id, name, building) ধরে:
- Relation: একটি নাম আর কয়েকটি attribute-এর স্কিমা, আর তার ওপর tuple-এর একটি set — বাস্তবে টেবিল।
- Tuple: একটি সারি, যেমন (1, 'CSE', 'Academic-1').
- Attribute: একটি কলাম-নাম, যেমন building.
- Domain: একটি attribute-এর সম্ভাব্য মানের সেট, যেমন dept_id-এর জন্য ধনাত্মক পূর্ণসংখ্যা।
- Degree: attribute-এর সংখ্যা — এখানে ৩।
- Cardinality: tuple-এর সংখ্যা — নমুনা ডেটায় ৪।
বৈশিষ্ট্য: (১) কোনো দুটি tuple হুবহু এক নয় (set); (২) tuple-এর ক্রমের অর্থ নেই; (৩) attribute-এর ক্রমের অর্থ নেই, নামেই চেনা; (৪) প্রতিটি ঘরে একটি atomic মান (1NF); (৫) প্রতিটি মান নিজের domain থেকে, অথবা NULL. মনে রাখবেন, SQL-এর টেবিল আসলে multiset — key না দিলে ডুপ্লিকেট সারি রাখা যায়, আর SELECT-এ DISTINCT না দিলে ডুপ্লিকেট আসে।
নম্বর কোথায়: প্রতিটি শব্দের এক লাইন আর একই টেবিল থেকে উদাহরণ; বৈশিষ্ট্যে অন্তত চারটি। SQL বনাম তত্ত্বের set/multiset পার্থক্যটি বললে বাড়তি নম্বর। পর্ব ০৫
ক-০৪Super key, candidate key, primary key, alternate key আর foreign key উদাহরণসহ ব্যাখ্যা করুন। প্রতিটি candidate key কি super key? উল্টোটা? — ৮ নম্বর (মাঝারি)
উদাহরণ টেবিল: student(student_id, nid, email, name, dept_id), যেখানে student_id, nid আর email প্রত্যেকটি আলাদাভাবে একজনকে চেনায়, আর নাম একাধিকজনের এক হতে পারে।
- Super key: attribute-এর যেকোনো সেট, যার মান দুটি সারিতে কখনো এক হয় না। যেমন {student_id}, {student_id, name}, {nid, email, dept_id} — অসংখ্য।
- Candidate key: minimal super key — একটি attribute সরালেই আর super key থাকে না। এখানে {student_id}, {nid}, {email}. {student_id, name} super key, কিন্তু candidate নয়, কারণ name সরালেও চলে।
- Primary key: candidate key-গুলোর একটি, যাকে ডিজাইনার মূল পরিচয় হিসেবে বেছে নেন — এখানে student_id (ছোট, স্থির, কখনো NULL নয়)।
- Alternate key: বাকি candidate key — nid আর email; SQL-এ এদের UNIQUE (আর দরকার হলে NOT NULL) দিয়ে রাখা হয়।
- Foreign key: এক টেবিলের কলাম, যার মান অন্য (বা একই) টেবিলের primary বা unique key-তে থাকতেই হবে, অথবা NULL. যেমন student.dept_id → departments.dept_id; db-uni-তে instructors.mentor_id → instructors.instructor_id একটি self-reference.
সম্পর্ক: প্রতিটি candidate key একটি super key (সংজ্ঞাতেই)। উল্টোটা সত্য নয় — {student_id, name} super key কিন্তু minimal নয়। আর প্রতিটি primary key একটি candidate key; প্রতিটি super key-এর ভেতরে অন্তত একটি candidate key থাকে।
নম্বর কোথায়: একই টেবিল দিয়ে পাঁচটির উদাহরণ (৫), “minimal” শব্দটি (১), প্রশ্নের শেষ অংশের দুই দিকের উত্তর একটি উল্টো উদাহরণসহ (২)। পর্ব ০৬
ক-০৫Entity integrity, referential integrity আর domain constraint কী? Parent সারি মুছলে child সারির কী হবে, তা কীভাবে ঠিক করা হয়? — ৬ নম্বর (মাঝারি)
Entity integrity: primary key-এর কোনো অংশ NULL হতে পারে না — না হলে সারিটিকে চেনা যায় না। Referential integrity: প্রতিটি non-NULL foreign key মানের জন্য parent টেবিলে মিল থাকা সারি থাকতেই হবে। Domain constraint: প্রতিটি মান কলামের টাইপ আর CHECK নিয়ম মানবে, যেমন CHECK (cgpa BETWEEN 0 AND 4).
Parent মুছলে: foreign key ঘোষণায় referential action দিয়ে ঠিক হয়:
ON DELETE NO ACTION(ডিফল্ট) বাRESTRICT: child থাকলে মোছা আটকে যায় (দুটির পার্থক্য শুধু চেক কখন হয় তাতে)।ON DELETE CASCADE: child-ও মুছে যায় — অর্ডার মুছলে তার order_items. ব্যাংকের লেনদেনের মতো ইতিহাসে বিপজ্জনক।ON DELETE SET NULL: child-এর FK NULL হয় — একজন শিক্ষক চলে গেলে courses.instructor_id NULL.ON DELETE SET DEFAULT: FK ডিফল্ট মানে ফেরে (সেই মানের parent থাকতে হবে)।
একই বিকল্প ON UPDATE-এও আছে। SQLite-এ foreign key চেক করতে প্রতিটি সংযোগে PRAGMA foreign_keys = ON দিতে হয় (এই পাতার এডিটরে তা চালু); PostgreSQL আর MySQL-এর InnoDB-তে ডিফল্টভাবেই চালু।
নম্বর কোথায়: তিনটি সংজ্ঞা আর প্রতিটির একটি উদাহরণ (৩), অন্তত তিনটি referential action আর কখন কোনটি (৩)। পর্ব ০৬ · পর্ব ২৩
ক-০৬Mapping cardinality আর participation constraint কী? Weak entity কী, তার key কীভাবে গঠিত হয়? উদাহরণ দিন। — ৬ নম্বর (মাঝারি)
Mapping cardinality: একটি relationship-এ এক পাশের একটি entity অন্য পাশের কতগুলোর সাথে যুক্ত হতে পারে — 1:1 (একজন মানুষ, একটি NID), 1:N (একটি বিভাগ, অনেক শিক্ষক), M:N (অনেক শিক্ষার্থী, অনেক কোর্স)।
Participation: total — প্রতিটি entity-কে relationship-এ থাকতেই হবে (প্রতিটি অর্ডারের একজন গ্রাহক; ER-এ দুই-রেখা); partial — না থাকলেও চলে (সব গ্রাহক অর্ডার দেননি; এক রেখা)। Total participation টেবিলে সাধারণত NOT NULL foreign key হয়।
Weak entity: যার নিজের attribute দিয়ে সারি আলাদা করা যায় না; একটি owner (strong) entity-র সাথে identifying relationship দিয়ে চেনা যায়। উদাহরণ: হাসপাতালের ওয়ার্ডে বেড — “বেড ৩” প্রতিটি ওয়ার্ডে আছে। বেডের partial key bed_no (ER-এ ভাঙা দাগে নিচে টানা); পূর্ণ key = owner-এর key + partial key = (ward_no, bed_no). ER-এ weak entity দুই-রেখার আয়তক্ষেত্র, identifying relationship দুই-রেখার রম্বস, আর weak entity-র participation সবসময় total.
নম্বর কোথায়: তিন রকম cardinality-র উদাহরণ (২), total/partial-এর সংজ্ঞা ও ER চিহ্ন (২), weak entity, partial key আর তার পূর্ণ key (২)। পর্ব ০৮
ক-০৭একটি হাসপাতালের ডেটাবেসের ER ডায়াগ্রাম আঁকুন, তারপর টেবিলে রূপান্তর করুন। নিয়ম: প্রতিটি ডাক্তার ঠিক একটি বিভাগে কাজ করেন; একজন রোগী অনেক ডাক্তারের কাছে যেতে পারেন, প্রতিটি সাক্ষাতের সময় রাখতে হবে; প্রতিটি ওয়ার্ডে কয়েকটি বেড, বেড-নম্বর শুধু ওয়ার্ডের ভেতরে আলাদা; রোগী বেডে ভর্তি হন, ভর্তির তারিখ রাখতে হবে। — ১২ নম্বর (কঠিন)
ধাপ ১ — entity আর key: DEPARTMENT(dept_id, name), DOCTOR(doctor_id, name, specialty), PATIENT(patient_id, name, phone), WARD(ward_no, kind), আর weak entity BED(bed_no) — owner WARD.
ধাপ ২ — relationship: WORKS_IN (DOCTOR N : 1 DEPARTMENT, ডাক্তারের দিকে total); CONSULTS (PATIENT M : N DOCTOR, attribute appt_time); HAS (WARD 1 : N BED, identifying); ADMITTED (PATIENT M : N BED সময়ের সাথে, attribute admitted_on).
হাসপাতালের ER ডায়াগ্রাম
Entities, a weak entity (BED), relationships with cardinality, and relationship attributes
ধাপ ৩ — mapping-এর নিয়ম প্রয়োগ: (ক) প্রতিটি strong entity একটি টেবিল; (খ) weak entity-র টেবিলে owner-এর key যোগ, PK = (ward_no, bed_no); (গ) 1:N সম্পর্কে N পাশের টেবিলে FK — doctor.dept_id, total বলে NOT NULL; (ঘ) প্রতিটি M:N সম্পর্ক একটি আলাদা টেবিল, দুই পাশের key আর সম্পর্কের attribute নিয়ে। একই রোগী একই ডাক্তারের কাছে একাধিকবার যেতে পারেন, তাই appt_time-ও PK-এর অংশ। নিচের এডিটরে পুরো স্কিমা চলে, তারপর নমুনা সারি আর একটি যাচাই-কোয়েরি:
CREATE TABLE department (dept_id INTEGER PRIMARY KEY, name TEXT NOT NULL UNIQUE);
CREATE TABLE doctor (doctor_id INTEGER PRIMARY KEY, name TEXT NOT NULL, specialty TEXT,
dept_id INTEGER NOT NULL REFERENCES department(dept_id)); -- N:1, total
CREATE TABLE patient (patient_id INTEGER PRIMARY KEY, name TEXT NOT NULL, phone TEXT);
CREATE TABLE ward (ward_no INTEGER PRIMARY KEY, kind TEXT);
CREATE TABLE bed (ward_no INTEGER REFERENCES ward(ward_no) ON DELETE CASCADE,
bed_no INTEGER, PRIMARY KEY (ward_no, bed_no)); -- weak entity
CREATE TABLE consults (patient_id INTEGER REFERENCES patient(patient_id),
doctor_id INTEGER REFERENCES doctor(doctor_id), appt_time TEXT,
PRIMARY KEY (patient_id, doctor_id, appt_time)); -- M:N
CREATE TABLE admitted (patient_id INTEGER NOT NULL REFERENCES patient(patient_id),
ward_no INTEGER, bed_no INTEGER, admitted_on TEXT,
PRIMARY KEY (ward_no, bed_no, admitted_on),
FOREIGN KEY (ward_no, bed_no) REFERENCES bed(ward_no, bed_no)); -- M:N
INSERT INTO department VALUES (1, 'Medicine'), (2, 'Cardiology');
INSERT INTO doctor VALUES (10, 'Dr. Rafiq', 'Physician', 1), (11, 'Dr. Laila', 'Cardiologist', 2);
INSERT INTO patient VALUES (100, 'Jamal', '01700000100'), (101, 'Shirin', NULL);
INSERT INTO ward VALUES (5, 'General');
INSERT INTO bed VALUES (5, 1), (5, 2);
INSERT INTO consults VALUES (100, 10, '2026-01-05 10:00'), (100, 11, '2026-01-06 11:30'),
(101, 11, '2026-01-06 12:00');
INSERT INTO admitted VALUES (100, 5, 2, '2026-01-07');
SELECT d.name AS doctor, COUNT(*) AS visits
FROM doctor d JOIN consults c ON c.doctor_id = d.doctor_id
GROUP BY d.doctor_id, d.name ORDER BY visits DESC;সাতটি CREATE TABLE-এর প্রতিটিতে ✓, তারপর INSERT-গুলো ২, ২, ২, ১, ২, ৩ আর ১টি সারি বদলায়। শেষ কোয়েরির ফল দুই সারি: Dr. Laila | 2 আর Dr. Rafiq | 1 — Jamal দুই ডাক্তারের কাছে গেছেন, Laila-র কাছে দুজন। যাচাই করে দেখুন: শেষ INSERT-এ বেড (5, 3) লিখলে “FOREIGN KEY constraint failed” — ওয়ার্ডে নেই এমন বেডে ভর্তি অসম্ভব, কারণ বেডের composite key ধরে FK দেওয়া হয়েছে।
একই কৌশলে লাইব্রেরি: BOOK(isbn, title), COPY (weak: copy_no, owner BOOK), MEMBER(member_id), আর LOAN (MEMBER M : N COPY, attribute issue_date, due_date) — টেবিলে copy(isbn, copy_no), loan(member_id, isbn, copy_no, issue_date, due_date).
নম্বর কোথায়: সব entity আর key (২), cardinality আর participation চিহ্নসহ ER (৪), weak entity আর partial key (২), প্রতিটি টেবিলের PK/FK সহ mapping (৪)। cardinality না লিখলে ER-এর অর্ধেক নম্বর যায়; M:N-কে FK দিয়ে সারতে গেলে mapping-এর। পর্ব ০৭ · পর্ব ১০ · পর্ব ১১
ক-০৮EER-এ specialization আর generalization কী? Disjoint/overlapping আর total/partial constraint উদাহরণসহ বোঝান। একটি specialization টেবিলে রূপান্তরের পদ্ধতিগুলো লিখুন। — ৮ নম্বর (মাঝারি)
সংজ্ঞা: Specialization হলো ওপর থেকে নিচে: একটি superclass-কে বিশেষ subclass-এ ভাগ করা (PERSON → STUDENT, EMPLOYEE). Generalization নিচ থেকে ওপরে: কয়েকটি entity-র সাধারণ অংশ নিয়ে superclass বানানো (CAR, BUS → VEHICLE). দুটিতেই subclass superclass-এর সব attribute উত্তরাধিকারে পায় (“IS-A”).
দুই জোড়া constraint:
- Disjoint (d): একটি entity সর্বোচ্চ একটি subclass-এ — ব্যাংক অ্যাকাউন্ট হয় SAVINGS, নয় CURRENT. Overlapping (o): একাধিকে হতে পারে — একজন PERSON একই সাথে STUDENT আর EMPLOYEE (টিচিং অ্যাসিস্ট্যান্ট)।
- Total: প্রতিটি superclass entity কোনো না কোনো subclass-এ (দুই-রেখা) — প্রতিটি অ্যাকাউন্ট SAVINGS বা CURRENT. Partial: কিছু entity কোনো subclass-এ নেই — অনেক PERSON ছাত্রও নন, কর্মীও নন।
দুই জোড়া স্বাধীন, তাই চারটি মিশ্রণই সম্ভব।
টেবিলে রূপান্তর:
- Superclass + প্রতিটি subclass আলাদা টেবিল: account(acc_no, balance), savings(acc_no PK/FK, interest_rate), current(acc_no PK/FK, overdraft_limit). সব ক্ষেত্রে চলে; পড়তে join লাগে।
- শুধু subclass টেবিল: savings(acc_no, balance, interest_rate) ইত্যাদি — শুধু total হলে চলে; overlapping হলে balance দুই জায়গায়।
- এক টেবিল, type কলাম: account(acc_no, balance, acc_type, interest_rate, overdraft_limit) — disjoint হলে; অপ্রযোজ্য কলাম NULL.
- এক টেবিল, boolean flag: person(id, name, is_student, is_employee, …) — overlapping হলে।
নম্বর কোথায়: দুই দিকের সংজ্ঞা (২), দুই জোড়া constraint, প্রতিটির উদাহরণ আর ER চিহ্ন (৩), অন্তত তিনটি mapping আর কখন কোনটি চলে না (৩)। পর্ব ০৯ · পর্ব ১০
৩ · অংশ খ — SQL লিখুন (মডিউল ৩–৪)
রিভিশনের জন্য: পর্ব ১২, পর্ব ১৩, পর্ব ১৪, পর্ব ১৫, পর্ব ১৬, পর্ব ১৭, পর্ব ১৮, পর্ব ১৯, পর্ব ২০, পর্ব ২১, পর্ব ২২, পর্ব ২৩, পর্ব ২৪, পর্ব ২৫, পর্ব ২৬, পর্ব ২৭, পর্ব ২৮, পর্ব ২৯, পর্ব ৩০, পর্ব ৩১.
লিখিত পরীক্ষায় সবচেয়ে বেশি আসে “এই স্কিমায় নিচের প্রশ্নগুলোর SQL লিখুন”। এখানে স্কিমা হলো কোর্সের বিশ্ববিদ্যালয় ডেটাবেস db-uni: departments(dept_id, name, building) — চারটি বিভাগ, English-এর ভবন NULL; instructors(instructor_id, name, dept_id, salary, mentor_id) — ছয়জন শিক্ষক, mentor_id আরেকজন শিক্ষককে দেখায়; students(student_id, name, dept_id, batch, cgpa) — আটজন, Fahim-এর CGPA আর Habib-এর বিভাগ NULL; courses(course_id, title, dept_id, credits, instructor_id) — সাতটি কোর্স; enrollments(student_id, course_id, term, grade) — ১৩টি ভর্তি, grade NULL মানে ফল আসেনি। পুরো ডেটা প্রতিটি এডিটরের নিচের “নমুনা ডেটাবেস” বাক্সে। খাতায় আগে লিখুন, তারপর উত্তর খুলে চালান — আর এডিটরে নিজের সংস্করণ বসিয়ে মিলিয়ে নিন।
খ-০১CSE বিভাগের যেসব শিক্ষার্থীর CGPA ৩.৫ বা তার বেশি, তাঁদের আইডি, নাম আর CGPA দেখান — বেশি CGPA আগে। (সহজ)
SELECT s.student_id, s.name, s.cgpa
FROM students s
JOIN departments d ON d.dept_id = s.dept_id
WHERE d.name = 'CSE' AND s.cgpa >= 3.5
ORDER BY s.cgpa DESC;তিনটি সারি: 2201 | Dilruba Khatun | 3.9, 2101 | Arif Hossain | 3.75, 2301 | Gulshan Ara | 3.55. Bristy (৩.৪০) বাদ। বিভাগের নাম departments-এ, তাই join; WHERE s.dept_id = 1 লিখলেও এই ডেটায় একই ফল আসে, কিন্তু প্রশ্নে নাম দেওয়া — আইডি ধরে নেওয়া মানে একটি অনুমান, যা খাতায় লিখে দিতে হয়।
নম্বর কোথায়: join শর্ত, দুটি শর্তই WHERE-এ, >= (প্রশ্নে “বা তার বেশি”), ORDER BY … DESC.
খ-০২প্রতিটি বিভাগের নাম আর সেই বিভাগের শিক্ষার্থীর সংখ্যা দেখান। যে বিভাগে কোনো শিক্ষার্থী নেই, সেটিও ০ সহ আসবে। (মাঝারি)
SELECT d.name AS dept, COUNT(s.student_id) AS students
FROM departments d
LEFT JOIN students s ON s.dept_id = d.dept_id
GROUP BY d.dept_id, d.name
ORDER BY students DESC, dept;চারটি সারি: CSE | 4, EEE | 2, BBA | 1, English | 0. দুটি ফাঁদ: (১) INNER JOIN দিলে English হারিয়ে যায়; (২) COUNT(*) দিলে English-এ ১ আসে, কারণ LEFT JOIN তার জন্য একটি সারি বানায় যার student-এর ঘরগুলো NULL. COUNT(s.student_id) NULL গোনে না, তাই ০। এডিটরে COUNT(*) বসিয়ে নিজে দেখুন। লক্ষ করুন, বিভাগহীন Habib কোনো সারিতে নেই — departments থেকে শুরু করায় তিনি বাইরে।
নম্বর কোথায়: LEFT JOIN-এর দিক (বিভাগ বাঁয়ে), COUNT(কলাম) বনাম COUNT(*)-এর যুক্তি, GROUP BY-তে key.
খ-০৩যেসব বিভাগে কোনো শিক্ষার্থী নেই, সেগুলোর নাম দেখান। একজন লিখলেন WHERE dept_id NOT IN (SELECT dept_id FROM students) — ফল কী আসবে, কেন? সঠিক কোয়েরি লিখুন। (মাঝারি)
-- ১. NOT IN: ফাঁদ
SELECT name FROM departments
WHERE dept_id NOT IN (SELECT dept_id FROM students);
-- ২. NOT EXISTS: সঠিক
SELECT d.name FROM departments d
WHERE NOT EXISTS (SELECT 1 FROM students s WHERE s.dept_id = d.dept_id);প্রথম কোয়েরি: (কোনো সারি নেই). দ্বিতীয়: English. কারণ subquery-র তালিকায় Habib-এর NULL আছে: 4 NOT IN (1, 2, 3, NULL) মানে 4 <> 1 AND 4 <> 2 AND 4 <> 3 AND 4 <> NULL, আর শেষ অংশটি UNKNOWN — তিন-মানের যুক্তিতে পুরোটা UNKNOWN, তাই সারি বাদ। NOT EXISTS প্রতিটি বিভাগের জন্য শুধু “মিল আছে কি না” দেখে, NULL-এ বিভ্রান্ত হয় না। বিকল্প: subquery-তে WHERE dept_id IS NOT NULL, অথবা LEFT JOIN … WHERE s.student_id IS NULL (anti join). এই আচরণ SQL standard-এর, তাই PostgreSQL আর MySQL-এও একই।
নম্বর কোথায়: ফাঁকা ফলের কথা বলা, NULL আর তিন-মানের যুক্তি দিয়ে কারণ, সঠিক বিকল্প।
খ-০৪যেসব বিভাগে অন্তত দুজন শিক্ষক আছেন, সেগুলোর নাম, শিক্ষক-সংখ্যা আর গড় বেতন দেখান। WHERE আর HAVING-এর পার্থক্য এই কোয়েরি দিয়ে বোঝান। (মাঝারি)
SELECT d.name AS dept, COUNT(*) AS instructors, AVG(i.salary) AS avg_salary
FROM instructors i
JOIN departments d ON d.dept_id = i.dept_id
GROUP BY d.dept_id, d.name
HAVING COUNT(*) >= 2
ORDER BY instructors DESC;দুটি সারি: CSE | 3 | 90000 আর EEE | 2 | 90000. BBA-তে একজন (Kamrul Hasan), তাই HAVING-এ বাদ। মজার ব্যাপার, তিন বিভাগের গড়ই ৯০,০০০ — CSE (১,২০,০০০ + ৮৫,০০০ + ৬৫,০০০) / ৩ আর EEE (১,১০,০০০ + ৭০,০০০) / ২। পার্থক্য: WHERE সারি ছাঁকে group তৈরির আগে, তাই সেখানে COUNT(*) লেখা যায় না; HAVING ছাঁকে group তৈরির পরে, aggregate-এর ওপর। যৌক্তিক ক্রম: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY.
নম্বর কোথায়: সঠিক HAVING, GROUP BY-তে সব non-aggregate কলাম, আর যৌক্তিক ক্রম দিয়ে পার্থক্যের ব্যাখ্যা।
খ-০৫প্রত্যেক শিক্ষকের নাম, বেতন আর তাঁর mentor-এর নাম ও বেতন দেখান; যাঁর mentor নেই, তিনিও আসবেন। কোনো শিক্ষক কি নিজের mentor-এর চেয়ে বেশি পান? (মাঝারি)
SELECT i.name AS instructor, i.salary,
m.name AS mentor, m.salary AS mentor_salary
FROM instructors i
LEFT JOIN instructors m ON m.instructor_id = i.mentor_id
ORDER BY i.instructor_id;ছয়টি সারি। তিনজনের mentor NULL (Dr. Anisur Rahman, Dr. Mahbub Alam, Kamrul Hasan); বাকি তিনটি: Shahana Parvin | 85000 | Dr. Anisur Rahman | 120000, Rumana Islam | 70000 | Dr. Mahbub Alam | 110000, Tasnim Chowdhury | 65000 | Shahana Parvin | 85000. একই টেবিল দুই alias-এ — self join. দ্বিতীয় প্রশ্নের উত্তর: না। শেষ লাইনের আগে WHERE i.salary > m.salary বসালে ফল খালি। খেয়াল করুন, এই WHERE বসালে mentor-হীন তিনজনও বাদ পড়েন (NULL-এর তুলনা UNKNOWN) — প্রশ্ন “বেশি পান কি না” হলে সেটিই ঠিক।
নম্বর কোথায়: দুই alias, LEFT JOIN-এর কারণ, join শর্তের দিক (m.instructor_id = i.mentor_id — উল্টো লিখলে “কার mentor আমি” আসে)।
খ-০৬Tasnim Chowdhury (instructor_id 6) যত কোর্স পড়ান, তার সবগুলোতে ভর্তি হয়েছেন এমন শিক্ষার্থীদের নাম দেখান। (কঠিন)
“সবগুলো” মানে relational division (গ-০১ দেখুন)। SQL-এ division নেই, তাই দ্বৈত নেতিবাচক: “এমন শিক্ষার্থী, যাঁর জন্য এমন কোনো কোর্স নেই, যাতে তিনি ভর্তি হননি।”
SELECT s.student_id, s.name
FROM students s
WHERE NOT EXISTS (
SELECT 1 FROM courses c
WHERE c.instructor_id = 6
AND NOT EXISTS (SELECT 1 FROM enrollments e
WHERE e.student_id = s.student_id
AND e.course_id = c.course_id));একটি সারি: 2101 | Arif Hossain. Tasnim পড়ান CSE301 আর CSE302; Arif দুটিতেই আছেন। Bristy আর Dilruba শুধু CSE301-এ, তাই বাদ। বিকল্প সমাধান গোনা দিয়ে: শিক্ষার্থী প্রতি এই কোর্সগুলোর DISTINCT সংখ্যা = মোট কোর্স-সংখ্যা (HAVING COUNT(DISTINCT e.course_id) = (SELECT COUNT(*) FROM courses WHERE instructor_id = 6)). একটি সূক্ষ্ম কিনারা: শিক্ষক কোনো কোর্সই না পড়ালে দ্বৈত NOT EXISTS সব শিক্ষার্থী দেয় (শূন্য সেট দিয়ে ভাগ — যুক্তিগতভাবে সত্য), কিন্তু join করে গোনার পদ্ধতি কোনো সারিই দেয় না, কারণ কোনো group-ই তৈরি হয় না। দুই পদ্ধতির এই পার্থক্য খাতায় এক লাইনে বললে বাড়তি নম্বর।
নম্বর কোথায়: “সবগুলো” শব্দ দেখে division চেনা, দ্বৈত NOT EXISTS-এর সঠিক correlated শর্ত, যুক্তির বাংলা বাক্য।
খ-০৭প্রতিটি বিভাগের সর্বোচ্চ বেতনের শিক্ষকের নাম আর বেতন দেখান (সমান হলে সবাই আসবেন)। Window function দিয়ে লিখুন, আর GROUP BY দিয়ে কেন সরাসরি হয় না তা বলুন। (মাঝারি)
SELECT dept, name, salary FROM (
SELECT d.name AS dept, i.name, i.salary,
RANK() OVER (PARTITION BY i.dept_id ORDER BY i.salary DESC) AS rk
FROM instructors i
JOIN departments d ON d.dept_id = i.dept_id
)
WHERE rk = 1
ORDER BY dept;তিনটি সারি: BBA | Kamrul Hasan | 90000, CSE | Dr. Anisur Rahman | 120000, EEE | Dr. Mahbub Alam | 110000. English-এ শিক্ষক নেই, তাই নেই। GROUP BY dept_id দিয়ে MAX(salary) পাওয়া যায়, কিন্তু সেই সারির নাম নয় — standard SQL-এ GROUP BY-তে নেই এমন কলাম (যেমন name) aggregate ছাড়া SELECT-এ রাখা যায় না। Window function সারি না মিশিয়ে প্রতিটি সারির পাশে র্যাংক বসায়। RANK সমান বেতনে দুজনকেই ১ দেয়; ROW_NUMBER দিলে একজন হারাত। window function WHERE-এ সরাসরি লেখা যায় না (WHERE আগে চলে), তাই বাইরের কোয়েরি লাগে।
নম্বর কোথায়: PARTITION BY-র কলাম, RANK বনাম ROW_NUMBER-এর পছন্দের কারণ, বাইরের ফিল্টার। বিকল্প: correlated subquery i.salary = (SELECT MAX(salary) … WHERE dept_id = i.dept_id).
খ-০৮সবচেয়ে বেশি শিক্ষার্থী ভর্তি হয়েছে কোন কোর্সে? সমান হলে সব কোর্স দেখাতে হবে। (মাঝারি)
WITH cnt AS (
SELECT c.course_id, c.title, COUNT(e.student_id) AS n
FROM courses c
LEFT JOIN enrollments e ON e.course_id = c.course_id
GROUP BY c.course_id, c.title
)
SELECT course_id, title, n FROM cnt
WHERE n = (SELECT MAX(n) FROM cnt);দুটি সারি: CSE201 | Data Structures | 3 আর CSE301 | Database Systems | 3. সাধারণ ভুল উত্তর ORDER BY n DESC LIMIT 1 — তা একটিই দেয়, আর কোনটি দেবে তা নিশ্চিত নয়। CTE একই গোনা দুবার ব্যবহার করতে দেয়। SQL Server-এ LIMIT নেই, সেখানে TOP 1 WITH TIES; PostgreSQL 13 থেকে আর Oracle 12c থেকে FETCH FIRST 1 ROWS WITH TIES.
নম্বর কোথায়: সমান মানের কথা ভাবা, প্রতি কোর্সে গোনা, MAX-এর সাথে তুলনা।
খ-০৯যেসব শিক্ষার্থীর CGPA নিজের বিভাগের গড় CGPA-র চেয়ে বেশি, তাঁদের নাম দেখান। CGPA বা বিভাগ NULL হলে কী হয়? (কঠিন)
SELECT s.name, s.dept_id, s.cgpa
FROM students s
WHERE s.cgpa > (SELECT AVG(s2.cgpa) FROM students s2
WHERE s2.dept_id = s.dept_id)
ORDER BY s.dept_id, s.cgpa DESC;দুটি সারি: Dilruba Khatun | 1 | 3.9 আর Arif Hossain | 1 | 3.75. CSE-র গড় (৩.৭৫ + ৩.৪০ + ৩.৯০ + ৩.৫৫) / ৪ = ৩.৬৫. EEE-তে Chayon-এর ২.৯৫ আর Fahim-এর NULL; AVG NULL বাদ দেয়, তাই গড় ২.৯৫ — Chayon “বেশি” নন, সমান। BBA-তে একজন, নিজের গড়ের সমান। Fahim-এর NULL তুলনা UNKNOWN, তাই বাদ। Habib-এর বিভাগ NULL: s2.dept_id = NULL কখনো সত্য নয়, subquery NULL দেয়, তুলনা UNKNOWN — বাদ। এটি correlated subquery: বাইরের প্রতিটি সারির জন্য ভেতরেরটি আবার চলে (বাস্তবে optimizer প্রায়ই একে GROUP BY-join-এ বদলে নেয়)।
নম্বর কোথায়: correlation শর্ত, AVG-এর NULL বাদ দেওয়া, NULL বিভাগের ব্যাখ্যা।
খ-১০প্রত্যেক শিক্ষার্থী কত ক্রেডিট অর্জন করেছেন দেখান — শুধু যেসব কোর্সে grade আছে আর F নয়। কোনো ক্রেডিট নেই এমন শিক্ষার্থীও ০ সহ আসবেন। (কঠিন)
SELECT s.student_id, s.name, COALESCE(SUM(c.credits), 0) AS earned
FROM students s
LEFT JOIN enrollments e
ON e.student_id = s.student_id
AND e.grade IS NOT NULL AND e.grade <> 'F'
LEFT JOIN courses c ON c.course_id = e.course_id
GROUP BY s.student_id, s.name
ORDER BY earned DESC, s.student_id;আটটি সারি: 2101 | Arif Hossain | 7.5, তারপর Bristy, Dilruba আর Gulshan — প্রত্যেকে 6, তারপর Chayon আর Emon 3, শেষে Fahim আর Habib 0. Dilruba-র CSE301-এর grade NULL, তাই সেটি গোনা হয়নি; Fahim-এর EEE101-এ F. মূল কৌশল: grade-এর শর্ত ON-এ. একই শর্ত WHERE-এ সরালে LEFT JOIN কার্যত INNER হয়ে যায় — Fahim আর Habib হারিয়ে যান, ফলে ছয়টি সারি। এডিটরে সরিয়ে দেখুন। COALESCE না দিলে তাঁদের ঘরে NULL আসত।
নম্বর কোথায়: ON বনাম WHERE-এ শর্তের পার্থক্য, COALESCE, দুটি LEFT JOIN-এর ক্রম।
৪ · অংশ গ — Relational algebra, FD আর normalization (মডিউল ৫)
রিভিশনের জন্য: পর্ব ৩২, পর্ব ৩৩, পর্ব ৩৪, পর্ব ৩৫, পর্ব ৩৬, পর্ব ৩৭, পর্ব ৩৮.
তত্ত্বের অংশে নম্বর সবচেয়ে “নিশ্চিত” — প্রতিটি ধাপে নম্বর। ভুলও নির্দিষ্ট: একটি candidate key বাদ, closure-এর একটি ধাপ ভুল, decomposition-এর পর যাচাই না করা। এখানকার প্রতিটি closure, key আর decomposition প্রোগ্রাম চালিয়ে মেলানো।
গ-০১db-uni স্কিমায় relational algebra-য় লিখুন: (ক) ২০২১ ব্যাচের যেসব শিক্ষার্থী কোনো CSE কোর্সে (dept_id = 1) ভর্তি, তাঁদের নাম; (খ) CSE201 নিয়েছেন কিন্তু CSE101 নেননি এমন শিক্ষার্থীর আইডি; (গ) সর্বোচ্চ বেতনের শিক্ষকের নাম, aggregate ছাড়া; (ঘ) Tasnim (instructor_id 6)-এর সব কোর্সে ভর্তি শিক্ষার্থীর আইডি। — ১০ নম্বর (কঠিন)
সংক্ষেপে S = students, E = enrollments, C = courses, I = instructors.
(ক) πname( σbatch=2021(S) ⋈ πstudent_id( E ⋈ πcourse_id(σdept_id=1(C)) ) )
ফাঁদটি লক্ষ করুন: S আর C দুটিতেই dept_id আছে। সরাসরি S ⋈ E ⋈ C লিখলে natural join নীরবে S.dept_id = C.dept_id শর্তও যোগ করে — অর্থাৎ “নিজের বিভাগের কোর্স”. তাই আগে π দিয়ে শুধু দরকারি কলাম রাখা হয়েছে। ফল: Arif Hossain, Bristy Saha.
(খ) πstudent_id(σcourse_id='CSE201'(E)) − πstudent_id(σcourse_id='CSE101'(E)). ফল: 2101, 2102 (Dilruba দুটিই নিয়েছেন)। দুই পাশ union-compatible — একই attribute.
(গ) πname(I) − πI.name( I ⋈I.salary < J.salary ρJ(I) ). মাঝের অংশ “যাঁর চেয়ে বেশি কেউ পান” — সর্বোচ্চ নন এমন সবাই; বাদ দিলে থাকেন সর্বোচ্চ। ফল: Dr. Anisur Rahman. নাম আলাদা-আলাদা ধরে নেওয়া হয়েছে; নিরাপদ রূপে instructor_id দিয়ে বাদ দিয়ে শেষে join করে নাম আনুন।
(ঘ) πstudent_id, course_id(E) ÷ πcourse_id(σinstructor_id=6(C)). ফল: 2101. ÷-এর মৌলিক রূপ (যদি নিষেধ থাকে): A ÷ B = πx(A) − πx( (πx(A) × B) − A ), যেখানে x = student_id.
নিচের এডিটর (ক), (খ) আর (গ)-এর SQL রূপ চালায়; (ঘ) খ-০৬-এ চালানো হয়েছে।
-- (ক)
SELECT DISTINCT s.name FROM students s
JOIN enrollments e ON e.student_id = s.student_id
JOIN courses c ON c.course_id = e.course_id
WHERE c.dept_id = 1 AND s.batch = 2021;
-- (খ) − = EXCEPT
SELECT student_id FROM enrollments WHERE course_id = 'CSE201'
EXCEPT
SELECT student_id FROM enrollments WHERE course_id = 'CSE101';
-- (গ) “যাঁর চেয়ে বেশি কেউ নেই”
SELECT i.name FROM instructors i
WHERE NOT EXISTS (SELECT 1 FROM instructors j WHERE j.salary > i.salary);তিনটি ফল-টেবিল: (ক) Arif Hossain, Bristy Saha; (খ) 2101, 2102; (গ) Dr. Anisur Rahman. (ক)-তে DISTINCT জরুরি — Arif তিনটি CSE কোর্সে, DISTINCT ছাড়া তাঁর নাম তিনবার আসত; relational algebra-য় π নিজেই ডুপ্লিকেট মোছে (set), SQL-এ নয়। Chayon ২০২১ ব্যাচের হলেও শুধু EEE101 নিয়েছেন।
নম্বর কোথায়: প্রতিটি expression-এ σ আগে, π শেষে; natural join-এর একই-নাম কলামের সমস্যা চেনা; − আর ÷-এর শর্ত (union-compatible, divisor-এর attribute ভাজ্যের অংশ)। expression tree আঁকলে বাড়তি পরিষ্কার। পর্ব ৩২ · পর্ব ৩৩
গ-০২Tuple relational calculus-এ লিখুন: CGPA ৩.৫-এর বেশি শিক্ষার্থীর নাম, আর গ-০১(ঘ)-এর প্রশ্নটি। Safe expression কী? Relational algebra আর calculus-এর ক্ষমতার সম্পর্ক কী? — ৬ নম্বর (মাঝারি)
প্রথমটি: { t | ∃s ∈ students ( s.cgpa > 3.5 ∧ t.name = s.name ) }
Division: { t | ∃s ∈ students ( t.student_id = s.student_id ∧ ∀c ∈ courses ( c.instructor_id = 6 ⇒ ∃e ∈ enrollments ( e.student_id = s.student_id ∧ e.course_id = c.course_id ) ) ) } — “সব” মানে ∀, আর ⇒ মানে “যদি Tasnim-এর কোর্স হয়, তবে ভর্তি আছে”. SQL-এর দ্বৈত NOT EXISTS ঠিক এই সূত্রের অনুবাদ, কারণ ∀x P(x) ≡ ¬∃x ¬P(x).
Safe: যে expression-এর ফল ডেটাবেসে থাকা মান (আর expression-এর ধ্রুবক) থেকেই আসে, অসীম হয় না। { t | ¬(t ∈ students) } unsafe — “যা students-এ নেই” এমন সব tuple অসীম।
ক্ষমতা: Codd দেখিয়েছিলেন, safe tuple calculus, safe domain calculus আর relational algebra-র প্রকাশক্ষমতা সমান। যে ভাষা অন্তত এটুকু পারে, সে relationally complete; SQL তা, আর aggregate ও recursion-এ তারও বেশি। Algebra “কীভাবে” (procedural), calculus “কী চাই” (declarative).
নম্বর কোথায়: ∃ আর ∀-এর সঠিক পরিসর, ⇒-এর ব্যবহার, unsafe-এর একটি উদাহরণ, সমতুল্যতার কথা। পর্ব ৩৪
গ-০৩Armstrong-এর axiom লিখুন। R(A, B, C, D, E), F = {A → BC, CD → E, B → D, E → A}. সব candidate key বের করুন। R কি 3NF-এ আছে? BCNF-এ? — ১০ নম্বর (মাঝারি)
Armstrong-এর axiom: (১) Reflexivity: Y ⊆ X হলে X → Y; (২) Augmentation: X → Y হলে XZ → YZ; (৩) Transitivity: X → Y আর Y → Z হলে X → Z. এরা sound (ভুল FD দেয় না) আর complete (F থেকে যা সত্য, সবই বের করা যায়)। এদের থেকে আসে union, decomposition আর pseudotransitivity.
Closure হিসাব:
A+ : A → BC দিয়ে {A,B,C}; B → D দিয়ে {A,B,C,D}; CD → E দিয়ে {A,B,C,D,E} ✓ key
E+ : E → A দিয়ে {A,E}; তারপর A+-এর মতো সব ✓ key
B+ : {B,D} C+ : {C} D+ : {D} ✗
BC+ : B → D দিয়ে {B,C,D}; CD → E: {B,C,D,E}; E → A: সব ✓ key
CD+ : CD → E দিয়ে {C,D,E}; E → A: {A,C,D,E}; A → BC: সব ✓ key
BD+ : {B,D} ✗
A বা E আছে এমন যেকোনো বড় সেট minimal নয়। A আর E ছাড়া বাকি তিন attribute B, C, D-র জোড়া দেখা হলো; তিনটির সেট BCD-তে BC আছে, তাই minimal নয়। Candidate key: A, E, BC, CD — চারটি।
Normal form: চারটি key মিলে A, B, C, D, E — সব attribute prime. 3NF-এর শর্ত (প্রতিটি non-trivial X → A-তে X superkey, অথবা A prime) তাই সব FD-তে পূরণ হয় — R 3NF-এ আছে। কিন্তু B → D-তে B superkey নয় (B+ = {B, D}), তাই BCNF নয়।
দ্রুত কৌশল: যে attribute কোনো FD-র ডান পাশে নেই, সেটি প্রতিটি key-তে থাকবেই — এখানে এমন কেউ নেই, তাই একক attribute থেকেই খোঁজা শুরু। আর যে attribute শুধু ডান পাশে আছে, সে কোনো key-তে থাকে না।
নম্বর কোথায়: তিনটি axiom (২), প্রতিটি closure-এর ধাপ (৪), চারটি key আর minimality-র যুক্তি (২), normal form-এর রায় সংজ্ঞাসহ (২)। একটি key বাদ পড়লে শেষের রায়ও ভুল হতে পারে — এখানে BC বা CD বাদ দিলে D-কে non-prime ভেবে “3NF নয়” লেখার ঝুঁকি। পর্ব ৩৫
গ-০৪F = {A → BC, B → C, A → B, AB → C, AC → D}-এর canonical cover বের করুন। প্রতিটি ধাপের কারণ লিখুন। — ৬ নম্বর (মাঝারি)
সংজ্ঞা: Canonical cover Fc হলো F-এর সমতুল্য এমন একটি সেট, যার কোনো FD-তে extraneous attribute নেই, কোনো FD অপ্রয়োজনীয় নয়, আর একই বাঁ পাশের FD-গুলো একত্র।
- ডান পাশ ভাঙা: A → B, A → C, B → C, A → B (দ্বিতীয়বার — বাদ), AB → C, AC → D.
- AB → C-এর বাঁ পাশ: F-এ A+ = {A, B, C, D}, যাতে C আছে, তাই B extraneous → A → C (আগেই আছে)।
- AC → D-এর বাঁ পাশ: A+-এ D আছে (A → C, তারপর AC → D), তাই C extraneous → A → D.
- অপ্রয়োজনীয় FD: এখন {A → B, A → C, B → C, A → D}. A → C বাদ দিলে A+ = {A, B, C, D} — A → B আর B → C দিয়েই C আসে, তাই A → C অপ্রয়োজনীয়। বাকি তিনটির কোনোটি বাদ দিলে সেই ডান পাশ আর আসে না।
- একত্র করা: Fc = {A → BD, B → C}.
যাচাই: Fc-এ A+ = {A, B, C, D}, B+ = {B, C} — F-এর সাথে মেলে, আর F-এর প্রতিটি FD Fc থেকে বের হয় (যেমন AC → D, কারণ A → D). ক্রম বদলালে (যেমন আগে B → C বাদ দেওয়ার চেষ্টা) কিছু প্রশ্নে অন্য একটি সঠিক canonical cover আসতে পারে — canonical cover সবসময় অনন্য নয়।
নম্বর কোথায়: প্রতিটি extraneous পরীক্ষায় কোন closure দেখা হলো তা লেখা (প্রতিটিতে ১), শেষে যাচাই (১)। পর্ব ৩৫
গ-০৫1NF, 2NF, 3NF আর BCNF সংজ্ঞায়িত করুন। প্রতিটির জন্য এমন একটি টেবিল দিন, যা আগের normal form-এ আছে কিন্তু এটিতে নেই, আর কোন anomaly হয় তা দেখান। — ১০ নম্বর (মাঝারি)
| Normal form | শর্ত | ভাঙার উদাহরণ | সমাধান |
|---|---|---|---|
| 1NF | প্রতিটি ঘরে একটি atomic মান, পুনরাবৃত্ত কলাম-দল নেই | student(id, name, phones) যেখানে phones = "017…, 018…" | student_phone(id, phone) |
| 2NF | 1NF, আর কোনো non-prime attribute কোনো candidate key-এর অংশের ওপর নির্ভর করে না | result(student_id, course_id, grade, student_name); key (student_id, course_id), কিন্তু student_id → student_name (partial dependency) | student(student_id, student_name), result(student_id, course_id, grade) |
| 3NF | প্রতিটি non-trivial X → A-তে X superkey, অথবা A prime | student(student_id, dept_id, building); student_id → dept_id → building (transitive dependency) | student(student_id, dept_id), department(dept_id, building) |
| BCNF | প্রতিটি non-trivial X → A-তে X superkey | teaches(sid, subject, teacher); {sid, subject} → teacher, teacher → subject; key {sid, subject} আর {sid, teacher}, সব attribute prime বলে 3NF | (teacher, subject), (sid, teacher) — কিন্তু {sid, subject} → teacher হারায় (গ-০৬) |
Anomaly: 2NF-এর উদাহরণে একজনের নাম প্রতিটি কোর্সের সারিতে — নাম বদলাতে সব সারি বদলাতে হয়, একটি বাদ পড়লে অসংগতি (update anomaly); কোনো কোর্সে ভর্তি না হওয়া শিক্ষার্থীকে রাখাই যায় না (insertion anomaly); শেষ কোর্সের সারি মুছলে শিক্ষার্থীর নামই হারায় (deletion anomaly). 3NF-এর উদাহরণে ভবনের নাম প্রতিটি শিক্ষার্থীর সারিতে; BCNF-এর উদাহরণে একজন শিক্ষকের বিষয় প্রতিটি শিক্ষার্থীর সারিতে।
ডেটা থেকে কোনো FD প্রমাণ করা যায় না — FD হলো বাস্তব জগতের নিয়ম। কিন্তু ডেটা একটি FD-কে খণ্ডন করতে পারে, আর anomaly চোখে দেখা যায়। নিচে গ-০৬-এর টেবিলের পাঁচটি সারি; প্রথম কোয়েরি দুটি FD পরীক্ষা করে, তারপর একটি সারিতে provost বদলানো হয়:
-- বাঁ পাশের একই মানে ডান পাশে একাধিক মান = FD ভাঙা
SELECT 'teacher -> subject' AS fd, COUNT(*) AS violations
FROM (SELECT teacher FROM r GROUP BY teacher HAVING COUNT(DISTINCT subject) > 1)
UNION ALL
SELECT 'hall -> provost', COUNT(*)
FROM (SELECT hall FROM r GROUP BY hall HAVING COUNT(DISTINCT provost) > 1);
-- update anomaly: Hall-A-র provost শুধু একটি সারিতে বদলানো হলো
UPDATE r SET provost = 'Prof. Nahar' WHERE sid = 2101 AND subject = 'DBMS';
SELECT hall, COUNT(DISTINCT provost) AS provosts FROM r GROUP BY hall;প্রথম ফল: teacher -> subject | 0 আর hall -> provost | 0 — এই পাঁচ সারিতে দুটি FD-ই খণ্ডিত হয়নি। তারপর ✓ UPDATE — ১টি সারি বদলেছে, আর শেষ ফল: Hall-A | 2, Hall-B | 1. Hall-A-র provost চারটি সারিতে লেখা ছিল; একটিতে বদলানোয় এখন একই হলের দুজন provost — ডেটা নিজের সাথেই অসংগত। hall → provost আলাদা টেবিলে থাকলে বদলাতে হতো একটিই সারি।
নম্বর কোথায়: চারটি নির্ভুল সংজ্ঞা (“non-prime” আর “অংশের” শব্দ দুটি জরুরি), প্রতিটির উদাহরণ ও সমাধান, তিন রকম anomaly. পর্ব ৩৬ · পর্ব ৩৭
গ-০৬R(sid, subject, teacher, hall, provost), F = {sid subject → teacher, teacher → subject, sid → hall, hall → provost}. (ক) সব candidate key আর R-এর সর্বোচ্চ normal form বের করুন। (খ) 3NF-এ decompose করুন। (গ) BCNF-এ decompose করুন। (ঘ) দুটির lossless join আর dependency preservation যাচাই করুন। — ১৫ নম্বর (কঠিন)
অর্থ: একজন শিক্ষার্থী একটি বিষয়ে একজন শিক্ষকের কাছে পড়েন; প্রতিটি শিক্ষক একটিই বিষয় পড়ান; প্রত্যেক শিক্ষার্থী একটি আবাসিক হলে থাকেন; প্রতিটি হলের একজন provost.
(ক) Key: sid কোনো ডান পাশে নেই, তাই প্রতিটি key-তে আছে। sid+ = {sid, hall, provost} — যথেষ্ট নয়। {sid, subject}+ = সব (teacher আসে), {sid, teacher}+ = সব (teacher → subject). hall আর provost শুধু ডান পাশ থেকে আসে, তাই কোনো key-তে লাগে না। Candidate key: {sid, subject}, {sid, teacher}. Prime: sid, subject, teacher; non-prime: hall, provost. sid → hall-এ non-prime hall একটি key-এর অংশের ওপর নির্ভর — R 1NF-এ আছে, 2NF-এ নেই।
(খ) 3NF synthesis: F নিজেই canonical (কোনো extraneous বা অপ্রয়োজনীয় FD নেই)। প্রতিটি FD থেকে একটি স্কিমা: (sid, subject, teacher), (teacher, subject), (sid, hall), (hall, provost). (teacher, subject) প্রথমটির ভেতরে — বাদ। প্রথমটিতে candidate key {sid, subject} আছে, তাই আলাদা key-স্কিমা লাগে না। ফল: R1(sid, subject, teacher), R2(sid, hall), R3(hall, provost). R1 3NF-এ আছে (teacher → subject-এ subject prime), কিন্তু BCNF নয়।
(গ) BCNF: নিচের stepper ধাপে ধাপে।
| টেবিল | |
| সব BCNF? | |
| lossless? | |
| সব FD আছে? |
- শুরু। পাঁচ attribute, চারটি FD, দুটি candidate key — (ক)-তে বের করা।
- নিয়ম-ভাঙা FD খোঁজা। BCNF-এ প্রতিটি non-trivial FD-র বাঁ পাশ superkey হতে হয়। শুধু প্রথমটি পাস করে; বাকি তিনটি ভাঙে। যেকোনোটি দিয়ে শুরু করা যায় — চূড়ান্ত ফল এখানে একই আসে, যদিও সাধারণভাবে ক্রম বদলালে ফল বদলাতে পারে।
- প্রথম ভাগ, sid → hall দিয়ে। বাঁ পাশের closure পুরোটা নিয়ে R1, আর R থেকে closure-এর বাড়তি অংশ সরিয়ে R2. সাধারণ অংশ sid, যা R1-এর key — তাই এই ভাগ lossless.
- R1 আবার ভাঙে। R1-এর ভেতরে hall → provost; hall এখানে key নয়। (hall, provost) আর (sid, hall). সাধারণ অংশ hall, প্রথমটির key — lossless.
- R2-ও ভাঙে। R2-তে teacher → subject; teacher superkey নয়। (teacher, subject) আর (sid, teacher). সাধারণ অংশ teacher, প্রথমটির key — lossless. এখন চারটি টেবিল আর কোনো নিয়ম-ভাঙা FD নেই।
- ফল। চারটি দুই-কলামের টেবিল। যেকোনো দুই-attribute relation BCNF-এ থাকে, কারণ যেকোনো non-trivial FD-র বাঁ পাশ একটি attribute, আর সেটি অন্যটিকে নির্ধারণ করলে সে নিজেই key. প্রতিটি ভাগ lossless বলে পুরো decomposition lossless.
- কী হারাল। sid subject → teacher-এর তিনটি attribute কোনো একটি টেবিলে একসাথে নেই। পরীক্ষার পদ্ধতি: Z = {sid, subject}; প্রতিটি টেবিল Ri-এর জন্য Z-এ যোগ করুন (Z ∩ Ri)+ ∩ Ri; Z-এ hall, provost আসে, teacher কখনো নয়। BCNF dependency preservation-এর নিশ্চয়তা দেয় না।
(ঘ) যাচাই:
- Lossless — দুই ভাগের নিয়ম: R-কে R1, R2-তে ভাঙলে lossless যদি এবং কেবল যদি (R1 ∩ R2) → R1 অথবা (R1 ∩ R2) → R2 F+-এ থাকে। প্রমাণের মূল ভাব (যদি অংশ): ধরুন সাধারণ অংশ R1-এর সব attribute নির্ধারণ করে। r1-এর একটি সারি আর r2-এর একটি সারি join হয় শুধু একই সাধারণ মানে; ওই মানের জন্য r1-এ একটিই সারি আছে (FD), তাই join-এর প্রতিটি সারি r-এর সেই সারিই, যার প্রক্ষেপণ r2-এর সারিটি — নতুন (spurious) সারি জন্মায় না। BCNF-এর প্রতিটি ভাগ এই নিয়মে পাস করেছে (stepper দেখুন)।
- Lossless — 3NF: synthesis-এর কোনো একটি স্কিমায় candidate key থাকলে ফল lossless (এখানে R1-এ {sid, subject})। একই কথা tableau বা chase পদ্ধতিতেও যাচাই করা হয়েছে: তিন সারির টেবিলে FD প্রয়োগ করলে একটি সারি সম্পূর্ণ “a” হয়ে যায়।
- Dependency preservation: 3NF-এ প্রতিটি FD কোনো না কোনো স্কিমার ভেতরে — সব রক্ষা। BCNF-এ sid subject → teacher হারায়।
একটি ভুল decomposition: (sid, subject), (subject, teacher), (sid, hall, provost) — প্রথম দুটির সাধারণ অংশ subject কিছুই নির্ধারণ করে না। গ-০৫-এর ডেটায় DBMS বিষয়ের দুজন শিক্ষক (Rahman, Parvin), তাই join-এ 2101-এর DBMS-এর সাথে Parvin-ও আসে — একটি spurious সারি। এটি lossy.
সিদ্ধান্ত: 3NF সব নিয়ম টেবিল-স্তরে রাখে (R1-এ PRIMARY KEY (sid, subject)), teacher → subject-এর জন্য একটু redundancy মেনে। BCNF redundancy শূন্য করে, কিন্তু হারানো নিয়মের জন্য join-ভিত্তিক চেক বা trigger লাগে। বাস্তবে প্রায়ই 3NF.
নম্বর কোথায়: key আর 2NF-এর রায় (৩), 3NF synthesis-এর তিন ধাপ (৩), BCNF-এর প্রতিটি ভাগ closure-সহ (৪), প্রতিটি lossless আর DP পরীক্ষা (৪), সিদ্ধান্ত (১)। পর্ব ৩৬ · পর্ব ৩৭
গ-০৭Multivalued dependency আর 4NF উদাহরণসহ ব্যাখ্যা করুন। BCNF-এ আছে কিন্তু 4NF-এ নেই এমন একটি টেবিল দিন। — ৬ নম্বর (মাঝারি)
সংজ্ঞা: X →→ Y (multivalued dependency) মানে X-এর একটি মানের জন্য Y-এর মানের সেট বাকি attribute (Z = R − X − Y)-এর মান থেকে স্বাধীন: X-এ মেলা যেকোনো দুটি সারি থাকলে তাদের Y আর Z অদলবদল করা সারিও টেবিলে থাকতে হয়। 4NF: প্রতিটি non-trivial X →→ Y-তে X superkey.
উদাহরণ: course_info(course, teacher, book) — CSE301 পড়ান দুজন (Tasnim, Shahana), আর বই দুটি (Silberschatz-এর বই, Elmasri-র বই); যেকোনো শিক্ষক যেকোনো বই ব্যবহার করেন। তাহলে CSE301-এর জন্য ২ × ২ = ৪টি সারি লাগে। কোনো non-trivial FD নেই, key তিনটি কলাম মিলে — তাই BCNF. কিন্তু course →→ teacher (আর course →→ book), course superkey নয় — 4NF নয়। নতুন একটি বই যোগ করতে দুটি সারি লাগে, একটি বাদ পড়লে ভুল অর্থ। সমাধান: (course, teacher) আর (course, book) — এই ভাগ lossless, কারণ course →→ teacher (Fagin-এর শর্ত: R1 ∩ R2 →→ R1 − R2).
নম্বর কোথায়: MVD-এর সংজ্ঞা অদলবদলের ভাষায় (২), BCNF কিন্তু 4NF নয় তার যুক্তি (২), decomposition (২)। প্রতিটি FD একটি MVD-ও, তাই 4NF ⇒ BCNF. পর্ব ৩৭
৫ · অংশ ঘ — স্টোরেজ, index আর query processing (মডিউল ৬)
রিভিশনের জন্য: পর্ব ৩৯, পর্ব ৪০, পর্ব ৪১, পর্ব ৪২, পর্ব ৪৩.
সংখ্যার প্রশ্নে নম্বর কাটে তিন জায়গায়: একক না বলা (page I/O, সারি নয়), ceiling ভুলে যাওয়া, আর কোন convention ধরছেন তা না লেখা। চিহ্ন পর্ব ৪২-এর: R-এর M page, S-এর N page, মেমোরিতে B buffer page.
ঘ-০১একটি খালি B+ tree-তে ক্রমে 25, 10, 40, 55, 15, 30, 5, 45, 50, 20 insert করুন। প্রতিটি node-এ সর্বোচ্চ ৩টি key. প্রতিটি split-এর পর গাছ আঁকুন। — ১০ নম্বর (কঠিন)
নিয়ম আগে লিখুন (পর্ব ৪০-এর মতো): leaf-এ ৪টি key হলে split — বাঁয়ে ২, ডানে ২, আর ডান leaf-এর প্রথম key-এর কপি parent-এ ওঠে। internal node-এ ৪টি key হলে বাঁয়ে প্রথম ২টি, তৃতীয়টি সরে ওপরে যায়, ডানে শেষটি। বই ভেদে split-এর ভাগ (কোন পাশে বেশি) আলাদা হয় — যেটি ধরছেন, খাতায় লিখে দিন; তাহলে অন্য নিয়মের উত্তরও পূর্ণ নম্বর পায়।
| key | |
| leaf | |
| উচ্চতা | |
| ঘটনা |
- প্রথম তিনটি। খালি গাছে root নিজেই leaf. 25, 10, 40 সাজানো ক্রমে বসে: [10 25 40] — পূর্ণ, কিন্তু সীমা ভাঙেনি।
- প্রথম split. 55 এলে চারটি key. বাঁয়ে [10 25], ডানে [40 55]; ডানের প্রথম key 40-এর কপি নতুন root-এ। 40 leaf-এও থাকে — সব data entry leaf-এ থাকে। উচ্চতা ১ থেকে ২।
- বাঁ leaf ভরে ভাঙে। 15 আর 30 দুটিই 40-এর ছোট, তাই বাঁ leaf-এ। চারটি হলে [10 15] আর [25 30]; 25-এর কপি root-এ: [25 │ 40].
- দুটি সরল insert. 5 যায় প্রথম leaf-এ (5 < 25), 45 যায় শেষ leaf-এ (45 ≥ 40). কোনোটিই চার ছোঁয় না।
- তৃতীয় leaf split. 50 শেষ leaf-এ: [40 45 50 55] → [40 45] আর [50 55]; 50-এর কপি root-এ। root-এ এখন ৩টি key — পূর্ণ, কিন্তু বৈধ।
- শিকল-বিক্রিয়া। 20 প্রথম leaf-এ, সেটি ভেঙে 15 ওপরে পাঠায়; root-এ হয় [15 25 40 50] — চারটি। internal split: প্রথম দুটি [15 │ 25] বাঁয়ে, তৃতীয় 40 সরে নতুন root, শেষ [50] ডানে। internal key কপি হয় না, কারণ internal node শুধু পথ দেখায়। উচ্চতা ৩.
- যাচাই। সব leaf একই গভীরতায়, শিকল ধরে পড়লে 5 থেকে 55 সাজানো। প্রতিটি internal key তার ডান subtree-র ক্ষুদ্রতম key-এর সমান বা ছোট। খোঁজে প্রতিটি স্তরে একটি node — ৩টি page I/O.
নম্বর কোথায়: split-এর নিয়ম লেখা (২), প্রতিটি split-এর পর গাছ (প্রতিটিতে ১–২), leaf-এ কপি আর internal-এ সরানোর পার্থক্য (২), চূড়ান্ত গাছ আর leaf শিকল (২)। শুধু শেষ গাছ আঁকলে অর্ধেকের কম। পর্ব ৪০ · DSA · B-tree
ঘ-০২ডেটাবেস index-এ binary search tree বা B-tree নয়, B+ tree কেন? ৪ KB page, ৮ বাইটের key আর ৮ বাইটের pointer হলে ১০ কোটি সারির জন্য B+ tree-এর উচ্চতা কত? Hash index কখন ভালো? — ৮ নম্বর (মাঝারি)
কেন B+ tree: (১) ডিস্কে খরচ page পড়ায়, তুলনায় নয়; একটি node = একটি page হলে শত শত শাখা (fanout), গাছ খুব বেঁটে — binary tree-তে ১০ কোটিতে প্রায় ২৭ স্তর। (২) সব data entry leaf-এ, leaf-গুলো শিকলে যুক্ত — range, ORDER BY আর prefix খোঁজ পাশাপাশি পড়ে। B-tree-তে data internal node-এও, তাই fanout কম আর range-এ ওঠা-নামা। (৩) সবসময় balanced.
উচ্চতা: একটি entry ৮ + ৮ = ১৬ বাইট, তাই fanout ≈ ৪০৯৬ / ১৬ = ২৫৬. সব node পূর্ণ ধরলে ২৫৬৩ ≈ ১.৬৮ কোটি < ১০ কোটি ≤ ২৫৬৪ ≈ ৪২৯ কোটি, তাই উচ্চতা ৪ (⌈log256 108⌉ = ⌈3.32⌉ = 4). বাস্তবে node দুই-তৃতীয়াংশ ভরা ধরলে fanout ≈ ১৭০; ১৭০৩ ≈ ৪৯ লাখ, ১৭০৪ ≈ ৮৩.৫ কোটি — তবুও ৪। ওপরের দুই স্তর সাধারণত buffer pool-এ থাকে, তাই একটি খোঁজে ডিস্কে প্রায় ২টি I/O, তারপর data page.
Hash index: শুধু সমতা (WHERE phone = ?)-তে গড়ে O(1) — একটি bucket. range, ORDER BY বা prefix-এ অকেজো, কারণ পাশাপাশি key আলাদা bucket-এ ছড়ানো। PostgreSQL-এ CREATE INDEX … USING hash আছে; MySQL-এর InnoDB নিজে থেকে কিছু খোঁজে adaptive hash index বানায়।
নম্বর কোথায়: fanout-এর ভূমিকা আর leaf শিকল (৩), সংখ্যাসহ উচ্চতার হিসাব (৩), hash-এর সুবিধা আর range-এ অক্ষমতা (২)। পর্ব ৪০ · পর্ব ৩৯
ঘ-০৩Clustered আর non-clustered index, dense আর sparse index-এর পার্থক্য লিখুন। একটি টেবিলে কতগুলো clustered index থাকতে পারে? Composite index-এ কলামের ক্রম কেন জরুরি? — ৬ নম্বর (মাঝারি)
Clustered: টেবিলের সারিগুলো নিজেই index-এর key-এর ক্রমে রাখা — বইয়ের পাতাগুলো যেমন পাতা-নম্বরের ক্রমে। তাই একটিই হতে পারে। InnoDB-তে primary key-ই clustered; SQL Server-এ যেকোনো একটি বেছে নেওয়া যায়; PostgreSQL-এর টেবিল heap, CLUSTER কমান্ড একবার সাজায় কিন্তু পরে ক্রম রক্ষা করে না। Non-clustered (secondary): আলাদা কাঠামো, key থেকে সারির ঠিকানা (বা InnoDB-তে primary key) — বইয়ের শেষের সূচির মতো; অনেকগুলো হতে পারে। range খোঁজে clustered-এ মিলের সারিগুলো পাশাপাশি page-এ, non-clustered-এ প্রতিটি সারির জন্য আলাদা page পড়তে হতে পারে।
Dense: প্রতিটি search-key মানের একটি entry. Sparse: শুধু কিছু মানের (যেমন প্রতিটি data page-এর প্রথম key) — ফাইল key-এর ক্রমে সাজানো থাকলেই সম্ভব। sparse ছোট, dense দ্রুত আর “আছে কি না” প্রশ্নে data না পড়েই উত্তর দেয়।
Composite-এর ক্রম: (dept_id, batch)-এর index সাজানো প্রথমে dept_id, তারপর batch — টেলিফোন বইয়ের মতো, পদবি তারপর নাম। তাই WHERE dept_id = 1 বা dept_id = 1 AND batch = 2021-এ কাজে আসে, কিন্তু শুধু batch = 2021-এ সাধারণত নয় (leftmost prefix নিয়ম)।
নম্বর কোথায়: দুই জোড়ার সংজ্ঞা আর একটি করে উপমা বা উদাহরণ (৪), “একটিই clustered” আর কারণ (১), composite-এর ক্রম (১)। পর্ব ৪০ · পর্ব ৪১
ঘ-০৪১০,০০০ page-এর একটি ফাইল ১১টি buffer page দিয়ে external merge sort করা হবে। কতগুলো pass, আর মোট কত page I/O? দুই pass-এ সাজাতে ন্যূনতম কত buffer লাগবে? — ৬ নম্বর (মাঝারি)
সূত্র: pass 0-এ B page করে পড়ে সাজিয়ে লেখা — ⌈N/B⌉টি run. প্রতিটি merge pass B − 1টি run মেলায় (একটি buffer output-এর জন্য)। মোট pass = 1 + ⌈logB−1⌈N/B⌉⌉, আর প্রতিটি pass পুরো ফাইল একবার পড়ে আর একবার লেখে — খরচ 2N × pass.
pass 0 : ⌈10000 / 11⌉ = 910 run (909.09 → ceiling) pass 1 : ⌈910 / 10⌉ = 91 run pass 2 : ⌈91 / 10⌉ = 10 run pass 3 : ⌈10 / 10⌉ = 1 run → সাজানো ফাইল মোট pass = 1 + 3 = 4 খরচ = 2 × 10000 × 4 = 80,000 page I/O
দুই pass-এ: pass 0-এর পর run-এর সংখ্যা এক merge-এ মেলাতে হবে: ⌈N/B⌉ ≤ B − 1, মোটামুটি B(B − 1) ≥ N. B = 100 হলে ⌈10000/100⌉ = 100 run, কিন্তু fan-in 99 — যথেষ্ট নয়। B = 101 হলে ⌈10000/101⌉ = 100 run ≤ 100 — হয়। ন্যূনতম ১০১টি buffer, খরচ 2 × 10000 × 2 = 40,000. সাধারণ নিয়ম: B ≈ √N হলেই দুই pass — তাই বাস্তবের প্রায় সব sort দুই pass-এ শেষ হয়।
Convention: কিছু বই শেষ pass-এর লেখা গোনে না (ফল সরাসরি পরের অপারেটরে যায়), তখন খরচ N(2⌈logB−1⌈N/B⌉⌉ + 1) = 10000 × 7 = 70,000. কোনটি ধরছেন, এক লাইনে লিখে দিন।
নম্বর কোথায়: সূত্র (১), প্রতিটি pass-এর run-সংখ্যা ceiling-সহ (২), মোট খরচ (১), দ্বিতীয় অংশের অসমতা আর ১০০ কেন যথেষ্ট নয় (২)। পর্ব ৪২
ঘ-০৫orders (M = ১,০০০ page) আর customers (N = ২০০ page)-এর equi-join, B = ২২ buffer. page nested loop, block nested loop (দুই দিকেই), sort-merge আর Grace hash join-এর খরচ বের করুন। কোনটি বেছে নেবেন? — ১০ নম্বর (কঠিন)
| অ্যালগরিদম | সূত্র | হিসাব | page I/O |
|---|---|---|---|
| Page nested loop (orders outer) | M + M·N | 1000 + 1000 × 200 | 201,000 |
| Block nested loop (orders outer) | M + ⌈M/(B−2)⌉·N | 1000 + ⌈1000/20⌉ × 200 = 1000 + 50 × 200 | 11,000 |
| Block nested loop (customers outer) | N + ⌈N/(B−2)⌉·M | 200 + ⌈200/20⌉ × 1000 = 200 + 10 × 1000 | 10,200 |
| Sort-merge | sort(M) + sort(N) + M + N | 6000 + 800 + 1200 | 8,000 |
| Grace hash | 3(M + N) | 3 × 1200 | 3,600 |
Sort-এর ভেতরের হিসাব: orders: ⌈1000/22⌉ = 46 run → ⌈46/21⌉ = 3 → 1; মোট ৩ pass, 2 × 1000 × 3 = 6,000. customers: ⌈200/22⌉ = 10 run → 1; ২ pass, 2 × 200 × 2 = 800. তারপর দুটি সাজানো ফাইল একবার পড়ে মেলানো 1,000 + 200. (ধরে নেওয়া: একই join key-এর সারিগুলো মেমোরিতে ধরে; সাজানো ফল লেখা গোনা হয়েছে।)
Grace hash-এর শর্ত: partition ধাপে দুই টেবিল পড়া আর লেখা (2(M + N)), probe ধাপে আবার পড়া (M + N). B − 1 = 21টি partition; customers-এর প্রতিটি partition প্রায় 200/21 ≈ 10 page, যা মেমোরিতে ধরে (B − 2 = 20). মোটা দাগে শর্ত B > √(ছোট টেবিল) — √200 ≈ 14.1 < 22 ✓.
সিদ্ধান্ত: Grace hash সবচেয়ে সস্তা (৩,৬০০)। তবে (১) join-টি non-equi হলে (<, BETWEEN) hash আর sort-merge চলে না — block nested loop; (২) ফল join key-এর ক্রমে লাগলে sort-merge-এর সাজানো ক্রম বিনা খরচে ORDER BY মেটায়; (৩) data skew হলে hash partition অসমান হয়। block nested loop-এ ছোট টেবিল outer — ১০,২০০ বনাম ১১,০০০। বাস্তব optimizer এই হিসাব statistics দিয়ে করে (পর্ব ৪৩)।
নম্বর কোথায়: প্রতিটি সূত্র (প্রতিটিতে ১), সংখ্যা বসানো আর ceiling (৪), hash-এর শর্ত (১), সিদ্ধান্ত আর কখন অন্যটি (১–২)। পর্ব ৪২ · পর্ব ৪৩
৬ · অংশ ঙ — Transaction, concurrency আর recovery (মডিউল ৭)
রিভিশনের জন্য: পর্ব ৪৪, পর্ব ৪৫, পর্ব ৪৬, পর্ব ৪৭, পর্ব ৪৮.
চিহ্ন: R1(A) মানে T1 item A পড়ে, W2(B) মানে T2 B লেখে। দীর্ঘ প্রশ্নে সাধারণত একটি schedule বা log থাকে; নম্বর আসে প্রতিটি জোড়া বা log record ধরে যুক্তি দেখালে।
ঙ-০১Transaction কী? ACID-এর প্রতিটি গুণ একটি টাকা পাঠানোর উদাহরণ দিয়ে ব্যাখ্যা করুন, আর DBMS-এর কোন অংশ কোন গুণ নিশ্চিত করে তা বলুন। — ৮ নম্বর (সহজ)
সংজ্ঞা: Transaction হলো ডেটাবেসের ওপর কয়েকটি অপারেশনের একটি যৌক্তিক একক, যা হয় পুরোটা ঘটে (COMMIT), নয় একেবারেই না (ROLLBACK). উদাহরণ: bKash-এ Rahim-এর অ্যাকাউন্ট থেকে Karima-র অ্যাকাউন্টে ৫০০ টাকা — দুটি UPDATE, একটি transaction.
- Atomicity: টাকা কাটার পর যোগ হওয়ার আগে সার্ভার বন্ধ হলে কাটাটিও ফিরে যাবে। নিশ্চিত করে recovery manager — undo log দিয়ে।
- Consistency: দুজনের মোট টাকা আগে-পরে সমান, আর কারও ব্যালান্স ঋণাত্মক নয়। নিশ্চিত করে অ্যাপের সঠিক যুক্তি আর DBMS-এর constraint (CHECK, FK).
- Isolation: একই সময়ে আরেকটি transaction মোট ব্যালান্স গুনলে সে মাঝপথের অবস্থা (কাটা হয়েছে, যোগ হয়নি) দেখবে না। নিশ্চিত করে concurrency control — lock বা MVCC.
- Durability: “পাঠানো সফল” বার্তা আসার পর বিদ্যুৎ গেলেও লেনদেন থাকবে। নিশ্চিত করে recovery manager — commit-এর আগে log ডিস্কে (WAL).
নিচে একটি ছোট accounts টেবিলে (id, name, balance; balance ঋণাত্মক হতে পারে না) transaction শুরু করে দুটি UPDATE, তারপর ROLLBACK:
BEGIN;
UPDATE accounts SET balance = balance - 500 WHERE id = 1;
UPDATE accounts SET balance = balance + 500 WHERE id = 2;
SELECT name, balance, (SELECT SUM(balance) FROM accounts) AS total FROM accounts;
ROLLBACK; -- COMMIT লিখলে বদল স্থায়ী হতো
SELECT name, balance FROM accounts;✓ BEGIN, দুটি UPDATE-এ ১টি করে সারি, তারপর transaction-এর ভেতরে: Rahim | 1500 | 2300, Karima | 800 | 2300 — মোট ২,৩০০ অপরিবর্তিত (consistency). ROLLBACK-এর পর: Rahim | 2000, Karima | 300 — যেন কিছুই ঘটেনি (atomicity). এবার প্রথম UPDATE-এ ৫০০-এর বদলে ৩০০০ লিখুন: CHECK ভাঙে, স্টেটমেন্টটি ব্যর্থ হয় আর তার কোনো বদল থাকে না (এডিটর প্রথম ত্রুটিতেই থেমে যায়)।
নম্বর কোথায়: সংজ্ঞা (১), চারটি গুণের প্রতিটির উদাহরণ (৪), প্রতিটির দায়িত্বে কোন অংশ (২), commit/rollback-এর উল্লেখ (১)। পর্ব ৪৪
ঙ-০২Transaction-এর অবস্থাগুলোর (state) ছবি আঁকুন আর প্রতিটি অবস্থা ব্যাখ্যা করুন। — ৫ নম্বর (সহজ)
শেষ স্টেটমেন্ট চলল log ডিস্কে
┌────────┐ ──────────────▶ ┌──────────────────┐ ─────────▶ ┌───────────┐
│ active │ │ partially │ │ committed │
└────────┘ │ committed │ └───────────┘
│ ত্রুটি └──────────────────┘
▼ │ লেখা ব্যর্থ
┌────────┐ ◀────────────────────────┘
│ failed │ ── rollback ──▶ ┌─────────┐ ──▶ আবার শুরু বা বাতিল
└────────┘ │ aborted │
└─────────┘
Active: স্টেটমেন্ট চলছে। Partially committed: শেষ স্টেটমেন্ট শেষ, কিন্তু log ডিস্কে লেখা বাকি। Committed: commit record ডিস্কে, বদল স্থায়ী। Failed: ত্রুটি, constraint ভাঙা বা deadlock-এর victim. Aborted: rollback শেষ; এরপর restart (যেমন deadlock-এর পর) বা kill (যুক্তির ভুল)।
নম্বর কোথায়: পাঁচটি অবস্থা আর তীরের কারণসহ ছবি (৩), partially committed আর committed-এর পার্থক্য (১), aborted-এর পর দুই বিকল্প (১)। পর্ব ৪৪
ঙ-০৩S: R1(A), R2(B), W2(A), R3(A), W1(B), W3(B). S কি conflict serializable? Precedence graph এঁকে যুক্তি দিন; হলে সমতুল্য serial ক্রম লিখুন। — ৮ নম্বর (কঠিন)
নিয়ম: দুটি অপারেশন conflict করে যদি আলাদা transaction, একই item, আর অন্তত একটি write. প্রতিটি conflicting জোড়ায় আগের অপারেশনের transaction থেকে পরেরটির দিকে একটি edge — এই হলো precedence graph. Graph-এ cycle নেই ⇔ conflict serializable.
Item ধরে সাজানো (হাতে করার নিরাপদ কৌশল): A: R1, W2, R3. B: R2, W1, W3.
A: R1(A) → W2(A) RW T1 → T2 A: W2(A) → R3(A) WR T2 → T3 B: R2(B) → W1(B) RW T2 → T1 B: R2(B) → W3(B) RW T2 → T3 B: W1(B) → W3(B) WW T1 → T3 (R1(A) আর R3(A): দুটিই read — conflict নয়) graph: T1 ⇄ T2, T1 → T3, T2 → T3 cycle: T1 → T2 → T1 ⇒ conflict serializable নয়
নিচের এডিটরে schedule-টি একটি টেবিলে (pos, tx, op, item) রাখা; প্রথম কোয়েরি conflict জোড়া থেকে edge বানায়, দ্বিতীয়টি recursive CTE দিয়ে খোঁজে কোন transaction থেকে হেঁটে নিজের কাছে ফেরা যায়:
INSERT INTO ops VALUES (1,1,'R','A'), (2,2,'R','B'), (3,2,'W','A'),
(4,3,'R','A'), (5,1,'W','B'), (6,3,'W','B');
-- ১. edge: একই item, আলাদা transaction, আগে-পরে, অন্তত একটি W
SELECT 'T' || a.tx || ' -> T' || b.tx AS edge, COUNT(*) AS pairs
FROM ops a JOIN ops b
ON a.item = b.item AND a.tx <> b.tx AND a.pos < b.pos
WHERE a.op = 'W' OR b.op = 'W'
GROUP BY a.tx, b.tx ORDER BY a.tx, b.tx;
-- ২. cycle-এ আছে কোন transaction?
WITH RECURSIVE e(src, dst) AS (
SELECT DISTINCT a.tx, b.tx FROM ops a JOIN ops b
ON a.item = b.item AND a.tx <> b.tx AND a.pos < b.pos
WHERE a.op = 'W' OR b.op = 'W'),
walk(start, cur, len) AS (
SELECT src, dst, 1 FROM e
UNION ALL
SELECT w.start, e.dst, w.len + 1 FROM walk w JOIN e ON e.src = w.cur
WHERE w.cur <> w.start AND w.len < 3)
SELECT DISTINCT 'T' || start AS on_cycle FROM walk WHERE cur = start;প্রথম ফল চারটি edge: T1 -> T2 | 1, T1 -> T3 | 1, T2 -> T1 | 1, T2 -> T3 | 2 — T2 → T3 দুটি জোড়া থেকে (W2(A)-R3(A) আর R2(B)-W3(B)), কিন্তু graph-এ একটিই edge. দ্বিতীয় ফল: T1, T2 — দুজনেই cycle-এ। হাঁটার দৈর্ঘ্য transaction-সংখ্যা (৩)-এ সীমিত, যাতে recursion থামে। INSERT-এর দ্বিতীয় মান (2,2,'R','B')-তে 'B'-এর জায়গায় 'C' লিখে দেখুন: T2 আর B পড়ে না, T2 → T1 edge উধাও, দ্বিতীয় কোয়েরির ফল খালি। বাকি তিনটি edge (T1 → T2, T1 → T3, T2 → T3) থেকে topological sort-এ serial ক্রম T1, T2, T3.
বাড়তি পর্যবেক্ষণ: strict 2PL-এ এই schedule ঘটতেই পারত না। T1 ধরে S(A), T2 ধরে S(B); W2(A)-র জন্য T2 অপেক্ষা করে T1-এর, W1(B)-র জন্য T1 অপেক্ষা করে T2-এর — deadlock. অর্থাৎ যে cycle precedence graph-এ ধরা পড়ে, lock-ভিত্তিক DBMS-এ সেটিই wait-for graph-এর cycle হয়ে দেখা দেয়, আর একটি victim abort হয় (ঙ-০৪)।
নম্বর কোথায়: প্রতিটি conflicting জোড়া ধরন আর দিকসহ (৪), graph (২), cycle আর সিদ্ধান্ত (২)। serializable হলে topological sort-এ serial ক্রম লিখতে হতো। পর্ব ৪৫
ঙ-০৪Two-phase locking কী, আর কেন তা conflict serializability দেয়? Strict 2PL কেন দরকার? 2PL-এ deadlock কীভাবে সামলানো হয় — wait-die আর wound-wait উদাহরণসহ লিখুন। — ১২ নম্বর (কঠিন)
সংজ্ঞা: Two-phase locking-এ প্রতিটি transaction দুই পর্বে চলে: growing — শুধু lock নেয়, ছাড়ে না; shrinking — শুধু ছাড়ে, নতুন নেয় না। প্রথম lock ছাড়ার মুহূর্তের ঠিক আগে transaction-এর হাতে সবচেয়ে বেশি lock — এই বিন্দু তার lock point. Read-এর জন্য shared (S), write-এর জন্য exclusive (X) lock; S-S মেলে, বাকি সব জোড়া অপেক্ষা করায়।
কেন serializable (প্রমাণের ছক): precedence graph-এ edge Ti → Tj থাকলে Ti আর Tj একই item-এ conflicting lock চেয়েছে, আর Ti আগে পেয়েছে; Tj পেয়েছে Ti ছাড়ার পর। Ti ছাড়ে নিজের lock point-এর পর, Tj নেয় নিজের lock point-এর আগে — তাই lock point(Ti) < lock point(Tj). একটি cycle T1 → T2 → … → T1 মানে lock point(T1) < lock point(T1) — অসম্ভব। তাই graph acyclic, আর lock point-এর ক্রমই একটি সমতুল্য serial ক্রম। ∎
Strict 2PL: সাধারণ 2PL-এ T1 commit-এর আগে X lock ছাড়লে T2 uncommitted মান পড়তে পারে; পরে T1 abort করলে T2-কেও — cascading abort, আর T2 আগেই commit করে থাকলে schedule recoverable-ই থাকে না। Strict 2PL-এ সব X lock commit বা abort পর্যন্ত ধরে রাখা হয় — ফল strict schedule. Rigorous 2PL-এ S lock-ও শেষ পর্যন্ত; বাস্তবের lock-ভিত্তিক DBMS এ দুটির একটি চালায়।
Deadlock: 2PL deadlock ঠেকায় না (ঙ-০৩-এর শেষ অনুচ্ছেদ)। তিন পথ: (১) detection — wait-for graph-এ cycle খুঁজে একটি victim (সাধারণত সবচেয়ে কম কাজ করা) abort — PostgreSQL, InnoDB আর SQL Server এভাবে; (২) timeout — বেশিক্ষণ অপেক্ষা করলে abort; (৩) prevention — timestamp দিয়ে অপেক্ষার দিক একমুখী রাখা:
| ঘটনা (ts ছোট = পুরোনো) | Wait-die | Wound-wait |
|---|---|---|
| TA (ts 100) চায় item, ধরে আছে TB (ts 200) — পুরোনো চাইছে | TA অপেক্ষা করে | TB abort (wound), TA পায় |
| TC (ts 300) চায় item, ধরে আছে TB (ts 200) — নতুন চাইছে | TC abort (die) | TC অপেক্ষা করে |
Wait-die-এ শুধু পুরোনোরা অপেক্ষা করে, wound-wait-এ শুধু নতুনরা — তাই অপেক্ষার শিকল একমুখী, cycle অসম্ভব। abort হওয়া transaction পুরোনো timestamp নিয়েই ফেরে, তাই একসময় সে সবচেয়ে পুরোনো হয় — starvation নেই। ঙ-০৩-এর schedule-এ T1 (পুরোনো) আর T2: wait-die-এ W2(A) চাইতেই T2 মরে; wound-wait-এ T2 প্রথমে অপেক্ষা করে, তারপর T1 W1(B) চাইলে T2-কে আহত করে — দুই নিয়মেই T2 abort, T1 এগোয়।
নম্বর কোথায়: দুই পর্ব আর lock point (২), serializability-র যুক্তি (৩), strict 2PL আর cascading abort (২), deadlock-এর তিন পথ (২), দুই নিয়মের টেবিল আর কেন cycle হয় না (৩)। পর্ব ৪৬
ঙ-০৫SQL-এর চারটি isolation level আর dirty read, non-repeatable read আর phantom read ব্যাখ্যা করুন। Snapshot isolation-এ write skew কী? জনপ্রিয় DBMS-এর ডিফল্ট level কী? — ১০ নম্বর (মাঝারি)
Anomaly:
- Dirty read: T2 পড়ে T1-এর এমন লেখা, যা এখনো commit হয়নি; পরে T1 rollback করলে T2 এমন মান দেখেছে যা কখনো ছিলই না।
- Non-repeatable read: T1 একই সারি দুবার পড়ে দুই মান পায়, কারণ মাঝে T2 সেটি বদলে commit করেছে।
- Phantom: T1 একই শর্তের কোয়েরি দুবার চালিয়ে আলাদা সারির সেট পায় — মাঝে T2 শর্তে পড়ে এমন সারি insert করেছে।
| Level (SQL standard) | Dirty read | Non-repeatable | Phantom |
|---|---|---|---|
| READ UNCOMMITTED | সম্ভব | সম্ভব | সম্ভব |
| READ COMMITTED | না | সম্ভব | সম্ভব |
| REPEATABLE READ | না | না | সম্ভব |
| SERIALIZABLE | না | না | না |
Write skew: হাসপাতালের নিয়ম “রাতে অন্তত একজন ডাক্তার ডিউটিতে”. দুজন ডাক্তার একসাথে ছুটি চান। দুটি transaction একই snapshot থেকে পড়ে দেখে “আরেকজন আছেন”, প্রত্যেকে নিজের সারি বদলায় — কোনো সারিতে দুজন একসাথে লেখেনি, তাই snapshot isolation আটকায় না; দুটিই commit, কেউ ডিউটিতে নেই। প্রতিকার: SERIALIZABLE (PostgreSQL-এর SSI এটি ধরে abort করে), অথবা SELECT … FOR UPDATE দিয়ে পড়া সারি lock করা।
ডিফল্ট: PostgreSQL, Oracle আর SQL Server-এ READ COMMITTED; MySQL InnoDB-তে REPEATABLE READ. বাস্তবের আচরণ নামের চেয়ে আলাদা হতে পারে: PostgreSQL-এর REPEATABLE READ আসলে snapshot isolation — phantom-ও দেখায় না, কিন্তু write skew ঘটতে দেয়; Oracle-এর “SERIALIZABLE”-ও snapshot isolation. SQLite-এ একসাথে একজনই লেখে, তাই সাধারণ ব্যবহারে আচরণ serializable.
নম্বর কোথায়: তিনটি anomaly-র সংজ্ঞা দুই transaction-এর ক্রমসহ (৩), টেবিল (৩), write skew-এর উদাহরণ (২), ডিফল্ট আর নাম-বনাম-আচরণের সতর্কতা (২)। পর্ব ৪৭
ঙ-০৬Immediate update আর checkpoint ব্যবহার করা একটি log দেওয়া আছে (নিচে)। crash-এর পর কোন transaction redo আর কোনটি undo হবে, আর A, B, C, D-এর চূড়ান্ত মান কত? WAL-এর নিয়ম আর ARIES-এর তিন ধাপ ব্যাখ্যা করুন। — ১২ নম্বর (কঠিন)
1 <T1 start>
2 <T1, A, 1000, 950> (item, পুরোনো মান, নতুন মান)
3 <T2 start>
4 <T2, C, 700, 600>
5 <T1 commit>
6 <checkpoint {T2}> (এই মুহূর্তে সক্রিয়: T2)
7 <T3 start>
8 <T3, B, 2000, 2050>
9 <T2, D, 500, 450>
10 <T3 commit>
11 <T4 start>
12 <T4, A, 950, 900>
── crash ──
WAL-এর নিয়ম: (১) কোনো data page ডিস্কে লেখার আগে সেই page-এর বদলের log record ডিস্কে; (২) commit সফল বলার আগে সেই transaction-এর সব log record (commit record-সহ) ডিস্কে। প্রথমটি undo সম্ভব করে, দ্বিতীয়টি redo.
বিশ্লেষণ:
- T1: checkpoint-এর আগেই commit; checkpoint-এ তার বদল ডিস্কে লেখা হয়ে গেছে — কিছুই করতে হবে না।
- T3: checkpoint-এর পরে শুরু, commit record আছে — redo: B = 2050.
- T2: checkpoint-এ সক্রিয়, commit নেই — undo: D = 500, C = 700 (উল্টো ক্রমে, log-এ checkpoint পেরিয়ে <T2 start> পর্যন্ত পিছিয়ে)।
- T4: commit নেই — undo: A = 950.
পর্ব ৪৮-এর পদ্ধতিতে: প্রথমে checkpoint থেকে সামনে সব update আবার প্রয়োগ (B = 2050, D = 450, A = 900) আর undo-তালিকা বানানো — {T2} দিয়ে শুরু, T3 start-এ যোগ, T3 commit-এ বাদ, T4 start-এ যোগ = {T2, T4}; তারপর পেছন দিকে T4 আর T2-এর update-গুলো পুরোনো মানে ফেরানো, প্রতিটির জন্য redo-only record আর শেষে <T2 abort>, <T4 abort>. চূড়ান্ত: A = 950, B = 2050, C = 700, D = 500.
ARIES (C. Mohan ও সহকর্মীরা, ১৯৯২): প্রতিটি log record-এর একটি LSN, প্রতিটি page-এ শেষ প্রয়োগ হওয়া record-এর pageLSN.
- Analysis: শেষ checkpoint থেকে log পড়ে transaction table (কে সক্রিয় ছিল) আর dirty page table (কোন page-এর বদল হয়তো ডিস্কে পৌঁছায়নি, আর তার প্রথম বদলের recLSN) পুনর্গঠন; redo কোথা থেকে শুরু — dirty page-গুলোর ক্ষুদ্রতম recLSN.
- Redo: “ইতিহাস পুনরাবৃত্তি” — সেখান থেকে loser-সহ সব update আবার প্রয়োগ, তবে শুধু যেখানে page-এর pageLSN record-এর LSN-এর ছোট; ফলে crash-এর মুহূর্তের অবস্থা ফেরে।
- Undo: loser transaction-গুলোর update পেছন দিকে ফেরানো; প্রতিটি ফেরানোর জন্য একটি CLR লেখা, যার undoNextLSN বলে এরপর কোনটি — তাই undo-র মাঝে আবার crash হলেও একই কাজ দুবার হয় না।
নম্বর কোথায়: WAL-এর দুই নিয়ম (২), প্রতিটি transaction-এর রায় আর কারণ (৪), চূড়ান্ত মান (২), ARIES-এর তিন ধাপ আর CLR (৪)। checkpoint-এর আগের committed T1-কে redo করলেও ভুল নয় (idempotent), কিন্তু “কেন দরকার নেই” বলা প্রত্যাশিত। পর্ব ৪৮
৭ · অংশ চ — অ্যাপ, নিরাপত্তা, NoSQL আর বড় মাপের ডেটা (মডিউল ৮–৯)
রিভিশনের জন্য: পর্ব ৪৯, পর্ব ৫০, পর্ব ৫১, পর্ব ৫২, পর্ব ৫৩, পর্ব ৫৪, পর্ব ৫৫, পর্ব ৫৬, পর্ব ৫৭, পর্ব ৫৮, পর্ব ৫৯, পর্ব ৬০, পর্ব ৬১, পর্ব ৬২.
এই অংশের প্রশ্ন বেশিরভাগ তুলনার — “X বনাম Y”, “কখন কোনটি”. নম্বর আসে একই মাপকাঠিতে দুই পাশ মেলালে আর একটি বাস্তব পরিস্থিতিতে সিদ্ধান্ত দেখালে।
চ-০১SQL injection কী, কেন ঘটে? এটি প্রতিরোধের উপায়গুলো উদাহরণসহ লিখুন। — ৮ নম্বর (মাঝারি)
সংজ্ঞা: SQL injection এমন একটি দুর্বলতা, যেখানে ব্যবহারকারীর দেওয়া লেখা সরাসরি SQL string-এ জোড়া হয়, ফলে সেই লেখা ডেটা না থেকে কোয়েরির অংশ হয়ে যায় — আর কোয়েরির অর্থ বদলে দিতে পারে।
কেন ঘটে: ডেটা আর কোড একই string-এ মেশে। ধরুন লগইনে কোড লেখা হলো "… WHERE phone = '" + phone + "'". ইনপুটে একটি উদ্ধৃতিচিহ্ন (') থাকলেই string-এর সীমানা বদলে যায়, আর বাকি ইনপুট SQL হিসেবে পড়া হয় — ফল হতে পারে অন্যের ডেটা দেখা, পুরো টেবিল বদলানো বা মুছে ফেলা।
import sqlite3
conn = sqlite3.connect("shop.db")
phone = input("phone: ")
# ভুল: f"SELECT name FROM customers WHERE phone = '{phone}'"
# ঠিক: placeholder (?) — ইনপুট আলাদাভাবে, শুধু মান হিসেবে যায়
row = conn.execute("SELECT name FROM customers WHERE phone = ?", (phone,)).fetchone()
print(row)প্রতিরোধ:
- Parameterized query বা prepared statement: SQL-এর গঠন আগে পাঠানো হয়, মান পরে আলাদাভাবে — মান কখনো কোড হয় না। এটিই মূল প্রতিকার (Java-তে PreparedStatement, PHP-তে PDO-র prepare, Node-এ placeholder).
- Identifier-এর জন্য allow-list: টেবিল বা কলামের নাম (যেমন ORDER BY-এর কলাম) placeholder দিয়ে পাঠানো যায় না; জানা নামের তালিকা থেকে বেছে নিন।
- Least privilege: অ্যাপের ডেটাবেস ব্যবহারকারীকে শুধু দরকারি টেবিলে দরকারি অনুমতি দিন — DROP বা অন্য টেবিল পড়ার ক্ষমতা নয়। দুর্বলতা থাকলেও ক্ষতি সীমিত হয়।
- ইনপুট যাচাই: টাইপ, দৈর্ঘ্য আর format (ফোন নম্বর ১১ অঙ্ক) — সহায়ক স্তর, একা যথেষ্ট নয়।
- ORM আর stored procedure: নিরাপদ API ব্যবহার করলে সাহায্য করে, কিন্তু ভেতরে raw SQL-এ string জুড়লে একই দুর্বলতা ফেরে।
- ত্রুটির বার্তা লুকানো আর logging: ব্যবহারকারীকে ডেটাবেসের ভেতরের ত্রুটি না দেখানো; সন্দেহজনক অনুরোধ log করা।
নম্বর কোথায়: সংজ্ঞা আর “ডেটা কোড হয়ে যায়” কারণটি (৩), parameterized query কোডসহ (২), বাকি অন্তত তিনটি স্তর (৩)। “escape করলেই হয়” লিখলে নম্বর কাটে — escaping ভুল হওয়া সহজ, তাই প্রথম পছন্দ placeholder. পর্ব ৫১ · পর্ব ৪৯
চ-০২Full, incremental আর differential backup-এর পার্থক্য কী? Point-in-time recovery কীভাবে হয়? Synchronous আর asynchronous replication তুলনা করুন। — ৮ নম্বর (মাঝারি)
Backup: Full — পুরো কপি; ফেরানো সহজ, কিন্তু বড়। Incremental — শেষ যেকোনো backup-এর পরের বদল; ছোট, কিন্তু ফেরাতে full + প্রতিটি incremental ক্রমে। Differential — শেষ full-এর পরের সব বদল; ফেরাতে full + শেষ differential. আবার logical (SQL স্টেটমেন্ট, যেমন pg_dump) বনাম physical (ফাইলের কপি) — physical দ্রুত, logical অন্য version-এ নেওয়া সহজ।
Point-in-time recovery: একটি base backup, আর তারপর থেকে সব log (PostgreSQL-এ WAL archive, MySQL-এ binary log) রাখা হয়। ভুল করে বিকেল ৩:০৫-এ একটি টেবিল মুছে গেলে base backup ফিরিয়ে log প্রয়োগ করা হয় ৩:০৪ পর্যন্ত।
| মাপকাঠি | Synchronous | Asynchronous |
|---|---|---|
| Commit কখন সফল | replica-ও log পেয়েছে নিশ্চিত হলে | শুধু primary-তে লেখা হলেই |
| Primary নষ্ট হলে ডেটা হারানো | না (committed সব replica-য়) | শেষ কয়েক মুহূর্তের commit হারাতে পারে |
| লেখার গতি | ধীর — প্রতিটি commit-এ নেটওয়ার্কের এক যাত্রা | দ্রুত |
| Replica বন্ধ হলে | লেখা আটকে যেতে পারে | primary চলতে থাকে |
মনে রাখুন, replication backup নয়: ভুল করে চালানো DELETE replica-তেও সাথে সাথে পৌঁছায়। দুটি লক্ষ্য মাপা হয় RPO (কতটুকু ডেটা হারানো মেনে নেওয়া যায়) আর RTO (কতক্ষণে আবার চালু) দিয়ে।
নম্বর কোথায়: তিন backup আর ফেরানোর ধাপ (৩), PITR-এর দুই উপাদান (২), replication-এর টেবিল (২), “replication backup নয়” (১)। পর্ব ৫২
চ-০৩CAP theorem ব্যাখ্যা করুন। “তিনটির যেকোনো দুটি বেছে নিন” কথাটি কেন বিভ্রান্তিকর? PACELC কী যোগ করে? — ৮ নম্বর (মাঝারি)
সংজ্ঞা: একটি distributed ডেটাবেসে তিনটি গুণ: Consistency (C — প্রতিটি read সর্বশেষ সফল write দেখে, যেন একটিই কপি; এটি linearizability, ACID-এর C নয়), Availability (A — সচল প্রতিটি node প্রতিটি অনুরোধের উত্তর দেয়), Partition tolerance (P — node-গুলোর মাঝে বার্তা হারালেও সিস্টেম চলে)। CAP theorem (Eric Brewer-এর ২০০০ সালের অনুমান, Seth Gilbert আর Nancy Lynch-এর ২০০২ সালের প্রমাণ): network partition হলে C আর A একসাথে রাখা যায় না।
যুক্তি: দুটি node, ঢাকা আর চট্টগ্রাম, তার কেটে গেছে। ঢাকায় একটি write এল। চট্টগ্রামে একটি read এলে দুই পথ: পুরোনো মান দিয়ে উত্তর (A রাখে, C ভাঙে), অথবা ঢাকার সাথে যোগাযোগ না হওয়া পর্যন্ত উত্তর না দেওয়া বা ত্রুটি (C রাখে, A ভাঙে)।
কেন বিভ্রান্তিকর: নেটওয়ার্কে partition ঘটবেই, তাই P বাদ দেওয়ার সুযোগ নেই — আসল পছন্দ শুধু partition-এর সময়: CP (যেমন একক-leader-এর consensus-ভিত্তিক সিস্টেম, ব্যাংকের লেনদেন) বা AP (যেমন shopping cart বা like-গণনা, পরে মিলিয়ে নেওয়া — eventual consistency). আর partition না থাকলে C আর A দুটিই পাওয়া যায়।
PACELC (Daniel Abadi): Partition হলে A বনাম C; Else (স্বাভাবিক সময়ে) Latency বনাম Consistency. অর্থাৎ partition না থাকলেও প্রতিটি write সব replica-য় নিশ্চিত করতে সময় লাগে — তাই দ্রুত উত্তর আর পূর্ণ consistency-র মধ্যে প্রতিদিনই একটি দর-কষাকষি।
নম্বর কোথায়: তিনটি গুণের নির্ভুল সংজ্ঞা (৩), partition-এর উদাহরণে দুই পথ (২), “P বাধ্যতামূলক” যুক্তি আর CP/AP উদাহরণ (২), PACELC (১)। পর্ব ৫৪
চ-০৪SQL (relational) আর NoSQL ডেটাবেসের তুলনা করুন। NoSQL-এর চারটি পরিবারের উদাহরণ আর ব্যবহার লিখুন। একটি ই-কমার্স সাইটে কোথায় কোনটি ব্যবহার করবেন? — ১০ নম্বর (মাঝারি)
| মাপকাঠি | Relational (SQL) | NoSQL (সাধারণ প্রবণতা) |
|---|---|---|
| ডেটা মডেল | টেবিল, সারি, কলাম; join | key-value, document, wide-column, graph |
| স্কিমা | আগে থেকে ঘোষিত, constraint সহ | নমনীয় — প্রতিটি document আলাদা হতে পারে (schema-on-read) |
| Transaction | পূর্ণ ACID, বহু টেবিলে | প্রায়ই এক document বা এক key-তে atomic; অনেকে এখন বহু-document transaction-ও দেয় (যেমন MongoDB ৪.০ থেকে) |
| Scaling | প্রথাগতভাবে vertical; read replica; sharding সম্ভব কিন্তু কঠিন | শুরু থেকেই horizontal — sharding-এর জন্য নকশা |
| কোয়েরি | SQL — ad hoc, যেকোনো join | সিস্টেম-নির্দিষ্ট API; কোয়েরি-প্যাটার্ন জেনে ডেটা সাজাতে হয় |
| Consistency | strong | প্রায়ই tunable বা eventual (BASE) |
চার পরিবার: Key-value — Redis, DynamoDB: session, cache, rate limit. Document — MongoDB: পণ্যের ক্যাটালগ, যেখানে প্রতিটি পণ্যের বৈশিষ্ট্য আলাদা (মোবাইলের RAM, শাড়ির কাপড়)। Wide-column — Cassandra: বিপুল লেখা, যেমন সেন্সর বা event log. Graph — Neo4j: “যাঁরা এটি কিনেছেন তাঁরা আর কী কিনেছেন”, বন্ধুর বন্ধু।
ই-কমার্সে (polyglot persistence): অর্ডার, পেমেন্ট আর মজুত — relational, কারণ টাকার হিসাবে ACID আর constraint অপরিহার্য; session আর cache — Redis; বৈচিত্র্যময় পণ্য-বিবরণ — PostgreSQL-এর JSONB বা MongoDB; খোঁজ — Elasticsearch. তবে ছোট দলের জন্য একটি relational ডেটাবেসই প্রায় সব সামলায়; প্রতিটি নতুন সিস্টেম মানে নতুন backup, monitoring আর ব্যর্থতার উৎস।
নম্বর কোথায়: অন্তত পাঁচটি মাপকাঠির টেবিল (৪), চার পরিবার উদাহরণসহ (৪), পরিস্থিতিভিত্তিক সিদ্ধান্ত আর কারণ (২)। “NoSQL মানে স্কিমা নেই আর দ্রুত” ধরনের ঢালাও কথা নম্বর কাটায়। পর্ব ৫৬ · পর্ব ৫৭ · পর্ব ৫৮
চ-০৫OLTP আর OLAP-এর পার্থক্য লিখুন। Star schema কী? db-shop-এর বিক্রির জন্য একটি star schema আঁকুন। — ৮ নম্বর (মাঝারি)
OLTP (online transaction processing): অনেক ছোট লেনদেন — অর্ডার, টাকা পাঠানো; কয়েকটি সারি পড়া-লেখা, normalized স্কিমা, মিলিসেকেন্ডের উত্তর। OLAP (online analytical processing): বিশ্লেষণ — “তিন বছরের মাসিক বিক্রি”; লাখো সারির aggregate, প্রায় শুধু পড়া, denormalized স্কিমা, columnar স্টোরেজ, ডেটা আসে ETL দিয়ে।
Star schema: মাঝে একটি fact টেবিল — মাপা যায় এমন সংখ্যা (পরিমাণ, টাকা) আর প্রতিটি dimension-এর key; চারপাশে dimension টেবিল — “কে, কী, কবে, কোথায়”.
dim_date(date_key, date, month, quarter, year)
│
dim_product(product_key, │ dim_customer(customer_key,
name, category) ──── fact_sales ──── name, city)
(date_key, product_key, customer_key,
quantity, amount)
“২০২৫-এর সেপ্টেম্বরে Dhaka-র গ্রাহকদের Electronics বিক্রি” — fact_sales-কে তিনটি dimension-এর সাথে একটি করে join, তারপর SUM(amount). dimension-এ category নাম বারবার থাকে (denormalized) — ইচ্ছাকৃত, যাতে join কম হয়। dimension-কে আরও ভাঙলে (category আলাদা টেবিলে) সেটি snowflake schema. fact-এর grain (একটি সারি = একটি অর্ডারের একটি পণ্য) আগে ঠিক করতে হয়।
নম্বর কোথায়: অন্তত চারটি মাপকাঠিতে OLTP বনাম OLAP (৩), fact আর dimension-এর সংজ্ঞা (২), ছবি key-সহ (২), snowflake বা grain-এর উল্লেখ (১)। পর্ব ৫৫
চ-০৬Partitioning আর sharding কী? Range, hash আর directory-ভিত্তিক sharding-এর সুবিধা-অসুবিধা লিখুন। একটি ভালো shard key কেমন হয়? — ৮ নম্বর (মাঝারি)
সংজ্ঞা: Partitioning একটি বড় টেবিলকে ছোট অংশে ভাগ করা — horizontal-এ সারি, vertical-এ কলাম। Sharding হলো আলাদা সার্ভারে horizontal partitioning — প্রতিটি shard ডেটার একটি অংশের মালিক, যাতে লেখা আর জায়গা একটি সার্ভারের সীমা ছাড়ায়। Replication (প্রতিটি সার্ভারে পুরো কপি) থেকে আলাদা; দুটি প্রায়ই একসাথে চলে।
- Range (customer_id ১ থেকে ১০ লাখ shard ১-এ, …): range কোয়েরি দ্রুত, কিন্তু নতুন id সব শেষ shard-এ — hotspot.
- Hash (hash(customer_id) mod n): সমান বণ্টন, কিন্তু range কোয়েরি সব shard-এ যায়; n বদলালে প্রায় সব ডেটা সরে — তাই consistent hashing, যেখানে একটি shard যোগ করলে মোটামুটি 1/n ভাগ ডেটা সরে।
- Directory (একটি lookup টেবিল বলে কোন key কোন shard-এ): নমনীয়, কিন্তু lookup নিজেই একটি নির্ভরতা আর সম্ভাব্য বাধা।
ভালো shard key: (১) অনেক আলাদা মান (high cardinality) আর সমান বণ্টন — শহর ভালো নয়, ঢাকায় অর্ধেক গ্রাহক থাকলে একটি shard ভারী; (২) সবচেয়ে সাধারণ কোয়েরিতে থাকে, যাতে একটি shard-এই উত্তর মেলে (customer_id দিয়ে একজনের সব অর্ডার); (৩) সময়ের সাথে একমুখী বাড়ে না (শুধু তারিখ ভালো নয়)। ক্ষতি: shard-পেরোনো join আর transaction কঠিন ও ধীর, পরে key বদলানো ব্যয়বহুল।
নম্বর কোথায়: partitioning, sharding আর replication-এর পার্থক্য (২), তিন পদ্ধতি সুবিধা-অসুবিধাসহ (৩), shard key-এর তিন গুণ উদাহরণসহ (৩)। পর্ব ৫৪
৮ · ভাইভা — মুখে উত্তরের কৌশল আর মডিউলভিত্তিক দ্রুত প্রশ্ন
ভাইভায় প্রশ্ন আসে মুখে, উত্তরও দিতে হয় তখনই — আর পরীক্ষক আপনার প্রথম উত্তর শুনেই পরের প্রশ্ন বানান (follow-up প্রশ্ন)। “primary key কী?” থেকে তিন প্রশ্নে পৌঁছানো যায় “InnoDB-তে এলোমেলো UUID primary key দিলে insert ধীর হয় কেন?” পর্যন্ত। চাকরির ভাইভা বোর্ড আর ব্যাকএন্ড ইন্টারভিউতে একই দক্ষতা লাগে।
তিন বাক্যের কাঠামো
প্রশ্ন: “index কী?” গোছানো উত্তর: “index হলো এক বা কয়েকটি কলামের সাজানো আলাদা কাঠামো, সাধারণত B+ tree, যা পুরো টেবিল না পড়ে সারি খুঁজে দেয় (কী)। বইয়ের শেষের সূচির মতো (কেন)। কিন্তু প্রতিটি INSERT আর UPDATE-এ index-ও বদলাতে হয়, তাই অপ্রয়োজনীয় index লেখা ধীর করে (কী দামে)।” পনেরো সেকেন্ড, তিন বাক্য — আর পরীক্ষকের হাতে পরের প্রশ্নের তিনটি সূত্র।
চারটি অভ্যাস যা নম্বর এনে দেয়
- জোরে ভাবুন (think aloud): উত্তর সাথে সাথে না এলে ভাবনাটা বলুন — “sid কোনো ডান পাশে নেই, তাই প্রতিটি key-তে আছে… sid-এর closure-এ teacher আসে না… তাই sid-এর সাথে subject বা teacher লাগবে।” পথ ঠিক থাকলে ছোট ভুলও ক্ষমা পায়।
- টেবিল আঁকুন: কাগজ চাইতে দ্বিধা করবেন না। তিন সারির একটি টেবিলে LEFT JOIN-এর NULL বা dirty read-এর দুই transaction-এর সময়রেখা দেখানো দশ বাক্যের কাজ করে।
- ছোট উদাহরণ আগে: “ধরুন students-এ তিনটি সারি…” বলে শুরু করলে বিমূর্ত প্রশ্ন হাতে-ধরা যায়।
- প্রশ্ন নিশ্চিত করুন: “PostgreSQL না MySQL?”, “standard-এর সংজ্ঞা, না নির্দিষ্ট DBMS-এর আচরণ?” — উত্তর যেখানে DBMS বা সংজ্ঞাভেদে বদলায়, সেখানে জিজ্ঞেস করাই পেশাদারি।
যে প্রশ্নের উত্তর জানেন না — সৎভাবে সামলানো
- স্বীকার করুন: “পুরো নিশ্চিত নই” বলা দুর্বলতা নয়; ভুল কথা জোর দিয়ে বললে বাকি ঠিক উত্তর নিয়েও সন্দেহ জাগে।
- যা জানেন সেখান থেকে যুক্তি দিন: “ARIES-এর খুঁটিনাটি মনে নেই, তবে WAL-এ redo আর undo দুটিই লাগে, কারণ buffer pool যেকোনো সময় page লিখতে পারে…”.
- আন্দাজকে আন্দাজ বলুন, আর যাচাইয়ের উপায় বলুন: “আমার ধারণা MySQL-এর ডিফল্ট REPEATABLE READ; নিশ্চিত হতে ডকুমেন্টেশন দেখতাম।”
- এগিয়ে যান: একটি প্রশ্ন না পারা পুরো ভাইভা নয়।
ভাইভা কুইকফায়ার — দ্রুত প্রশ্ন, ছোট উত্তর
জোরে জোরে উত্তর বলুন, তারপর প্রশ্নে চেপে মেলান — প্রতিটিতে ২০–৩০ সেকেন্ডের বেশি নয়। উত্তরগুলো ইচ্ছা করে এক–তিন বাক্যে রাখা।
ভিত্তি ও ডিজাইন (পর্ব ০১–১১)
ভ-০১Data আর information-এর পার্থক্য কী? (সহজ)
Data হলো প্রক্রিয়াহীন তথ্যকণা — “2101, 3.75”; information হলো প্রসঙ্গসহ সাজানো অর্থ — “Arif-এর CGPA ৩.৭৫, বিভাগে দ্বিতীয়”. DBMS data রাখে, কোয়েরি তা থেকে information বানায়। পর্ব ০১
ভ-০২Schema আর instance-এর পার্থক্য কী? (সহজ)
Schema হলো ডেটাবেসের নকশা — কোন টেবিল, কোন কলাম, কোন constraint; সহজে বদলায় না। Instance হলো কোনো এক মুহূর্তে ভেতরের আসল ডেটা — প্রতিটি INSERT-এ বদলায়। ক্লাসের রেজিস্টার খাতার ছাপানো ঘরগুলো schema, আজকের হাজিরা instance. পর্ব ০৩
ভ-০৩System catalog বা data dictionary কী? (সহজ)
ডেটা সম্পর্কে ডেটা (metadata) — কোন টেবিল, কোন কলাম, কোন টাইপ, কোন index, কে কী অনুমতি পান — DBMS নিজের টেবিলেই রাখে। SQLite-এ sqlite_schema, PostgreSQL আর MySQL-এ information_schema; optimizer-এর statistics-ও এখানে। পর্ব ০৩
ভ-০৪Logical আর physical data independence — কোনটি কঠিন? (মাঝারি)
Logical কঠিন: টেবিল বা কলাম বদলালে অ্যাপের কোয়েরি সরাসরি ভাঙতে পারে, view দিয়ে সবসময় পুরো ঢাকা যায় না। Physical বদল (index, ফাইলের বিন্যাস) SQL-এর কাছে অদৃশ্য — শুধু গতি বদলায়, ফল নয়। পর্ব ০৩
ভ-০৫Primary key আর unique key-এর পার্থক্য কী? (সহজ)
টেবিলে primary key একটিই, আর তা কখনো NULL নয়; UNIQUE অনেকগুলো থাকতে পারে, আর standard SQL-এ (PostgreSQL, MySQL, SQLite) UNIQUE কলামে একাধিক NULL চলে, কারণ NULL-কে NULL-এর সমান ধরা হয় না — SQL Server এখানে ব্যতিক্রম, একটিই NULL দেয়। দুটিই ভেতরে একটি unique index বানায়; InnoDB-তে primary key-ই টেবিলের clustered ক্রম। পর্ব ০৬
ভ-০৬Foreign key কি NULL হতে পারে? (মাঝারি)
হ্যাঁ, NOT NULL না দিলে — NULL মানে “এখনো কোনো parent নেই”, আর referential integrity শুধু non-NULL মানের জন্য parent দাবি করে। db-uni-তে ENG101-এর instructor_id NULL. Total participation বোঝাতে FK-তে NOT NULL দিন। পর্ব ০৬
ভ-০৭Natural key না surrogate key — কোনটি primary key হবে? (মাঝারি)
Natural key (NID, ফোন) বাস্তব অর্থ বহন করে কিন্তু বদলাতে পারে, ফাঁকা থাকতে পারে বা গোপনীয়; surrogate key (স্বয়ংক্রিয় সংখ্যা বা UUID) অর্থহীন কিন্তু স্থির আর ছোট। সাধারণ পছন্দ: surrogate primary key, আর natural key-তে UNIQUE constraint — যাতে ডুপ্লিকেট তবুও আটকায়। পর্ব ০৬
ভ-০৮Weak entity কী? একটি উদাহরণ দিন। (সহজ)
যে entity নিজের attribute দিয়ে আলাদা করা যায় না, owner-এর key লাগে — যেমন ওয়ার্ডের বেড বা অর্ডারের লাইন-আইটেম। টেবিলে PK = owner-এর key + partial key, যেমন (ward_no, bed_no); owner মুছলে সাধারণত ON DELETE CASCADE. পর্ব ০৮
ভ-০৯M:N relationship-কে কেন আলাদা টেবিল বানাতে হয়? (সহজ)
কারণ একটি ঘরে একটিই মান থাকে (1NF): একজন শিক্ষার্থীর সারিতে অনেক কোর্স রাখা যায় না, আর কোর্সের সারিতে অনেক শিক্ষার্থীও না। তাই junction টেবিল — db-uni-র enrollments, দুই পাশের key আর সম্পর্কের attribute (term, grade) নিয়ে। পর্ব ১০
ভ-১০একটি multivalued attribute (যেমন একাধিক ফোন নম্বর) টেবিলে কীভাবে রাখবেন? (সহজ)
আলাদা টেবিলে: customer_phone(customer_id, phone), PK দুটি মিলে। phone1, phone2, phone3 কলাম বা কমা দিয়ে জোড়া string — দুটিই খোঁজা আর যাচাই কঠিন করে, আর দ্বিতীয়টি 1NF ভাঙে। পর্ব ১০
SQL (পর্ব ১২–৩১)
ভ-১১DELETE, TRUNCATE আর DROP-এর পার্থক্য কী? (সহজ)
DELETE সারি মোছে, WHERE নেয়, প্রতিটি সারি log করে আর trigger চালায় — ধীর, কিন্তু rollback সম্ভব। TRUNCATE সব সারি একবারে মোছে, WHERE নেয় না, সাধারণত দ্রুত আর সারি-প্রতি trigger চালায় না; PostgreSQL-এ transaction-এর ভেতরে rollback করা যায়, MySQL আর Oracle-এ এটি DDL-এর মতো সাথে সাথে commit হয়। DROP পুরো টেবিল — গঠন, index, অনুমতিসহ — সরিয়ে দেয়। SQLite-এ TRUNCATE নেই; WHERE-হীন DELETE দ্রুত পথে চলে। পর্ব ১৪
ভ-১২WHERE আর HAVING-এর পার্থক্য কী? (সহজ)
WHERE সারি ছাঁকে group তৈরির আগে, aggregate দেখতে পায় না; HAVING ছাঁকে group তৈরির পরে, aggregate-এর ওপর। যে শর্ত সারির ওপর, তা WHERE-এ দিলে কম সারি group-এ যায় — দ্রুতও। পর্ব ১৮
ভ-১৩COUNT(*), COUNT(col) আর COUNT(DISTINCT col)-এর পার্থক্য কী? (সহজ)
COUNT(*) সব সারি গোনে; COUNT(col) শুধু যেখানে col NULL নয়; COUNT(DISTINCT col) আলাদা non-NULL মান। db-uni-র students-এ COUNT(*) = ৮, COUNT(cgpa) = ৭, COUNT(DISTINCT dept_id) = ৩. পর্ব ১৮
ভ-১৪NULL = NULL কেন সত্য নয়? (মাঝারি)
NULL মানে “অজানা”; দুটি অজানা মান সমান কি না তা-ও অজানা, তাই ফল UNKNOWN — আর WHERE শুধু TRUE সারি রাখে। তাই IS NULL লিখতে হয়; NULL-সহ সমতা চাইলে standard-এ IS NOT DISTINCT FROM, SQLite-এ IS. পর্ব ১৬
ভ-১৫INNER JOIN আর LEFT JOIN-এর পার্থক্য কী? (সহজ)
INNER JOIN শুধু দুই পাশে মিল থাকা সারি দেয়; LEFT JOIN বাঁ টেবিলের সব সারি রাখে, মিল না থাকলে ডান পাশের ঘর NULL. “যাঁদের কোনো অর্ডার নেই, তাঁরাও” — এমন শব্দ দেখলেই LEFT JOIN. পর্ব ১৯
ভ-১৬UNION আর UNION ALL-এর পার্থক্য কী? (সহজ)
UNION দুই ফল জুড়ে ডুপ্লিকেট সরায় — তাই sort বা hash লাগে; UNION ALL সব রাখে আর দ্রুত। ডুপ্লিকেট সম্ভব না হলে বা দরকার হলে UNION ALL দিন। দুই পাশে কলামের সংখ্যা আর টাইপ মিলতে হয়। পর্ব ২২
ভ-১৭Correlated subquery কী? (মাঝারি)
যে subquery বাইরের কোয়েরির কোনো কলাম ব্যবহার করে, তাই যৌক্তিকভাবে বাইরের প্রতিটি সারির জন্য আবার চলে — যেমন “নিজের বিভাগের গড়ের চেয়ে বেশি CGPA” (খ-০৯)। optimizer প্রায়ই একে join-এ বদলে নেয়, তবে বড় টেবিলে EXPLAIN দেখে নিশ্চিত হওয়া ভালো। পর্ব ২১
ভ-১৮View আর materialized view-এর পার্থক্য কী? (মাঝারি)
View একটি সংরক্ষিত কোয়েরি — প্রতিবার পড়ার সময় চলে, ডেটা রাখে না, সবসময় সর্বশেষ। Materialized view ফলটি টেবিলের মতো রেখে দেয় — পড়া দ্রুত, কিন্তু refresh না করলে পুরোনো (PostgreSQL-এ REFRESH MATERIALIZED VIEW; SQLite আর MySQL-এ নিজস্ব নেই)। পর্ব ২৪
ভ-১৯ROW_NUMBER, RANK আর DENSE_RANK-এর পার্থক্য কী? (মাঝারি)
বেতন 120, 90, 90, 85 হলে: ROW_NUMBER দেয় 1, 2, 3, 4 (সমানেও আলাদা); RANK দেয় 1, 2, 2, 4 (ফাঁক থাকে); DENSE_RANK দেয় 1, 2, 2, 3 (ফাঁক নেই)। “প্রতি group-এ সর্বোচ্চ, সমান হলে সবাই” — RANK বা DENSE_RANK; “ঠিক একটি” — ROW_NUMBER. পর্ব ২৬
ভ-২০Trigger কখন ক্ষতিকর? (মাঝারি)
যখন ব্যবসার মূল যুক্তি অদৃশ্যভাবে trigger-এ লুকায়: কোড পড়ে বোঝা যায় না একটি INSERT আর কী কী বদলায়, এক trigger আরেকটিকে চালায় (cascading), bulk লেখা ধীর হয়, আর debug কঠিন। audit log বা ছোট নিয়ম রক্ষায় ভালো; জটিল কাজ অ্যাপে বা স্পষ্ট procedure-এ। পর্ব ২৯
তত্ত্ব ও normalization (পর্ব ৩২–৩৮)
ভ-২১Functional dependency কী? (সহজ)
X → Y মানে X-এর একই মানের যেকোনো দুটি সারিতে Y-এর মানও এক — X জানলে Y নির্ধারিত। যেমন student_id → name. এটি বাস্তব জগতের নিয়ম; ডেটা একে খণ্ডন করতে পারে, প্রমাণ নয়। পর্ব ৩৫
ভ-২২Normalization কেন করা হয়? (সহজ)
Redundancy কমাতে, যাতে একই তথ্য একাধিক জায়গায় না থাকে — ফলে update, insertion আর deletion anomaly দূর হয়, আর constraint দিয়ে নিয়ম রক্ষা সহজ হয়। পদ্ধতি: FD দেখে টেবিলকে lossless ভাবে ছোট টেবিলে ভাঙা। পর্ব ৩৬
ভ-২৩3NF আর BCNF-এর পার্থক্য এক বাক্যে বলুন। (মাঝারি)
BCNF-এ প্রতিটি non-trivial FD-র বাঁ পাশ superkey; 3NF এর সাথে একটি ছাড় দেয় — ডান পাশ prime হলেও চলে। এই ছাড়ের দাম একটু redundancy, লাভ — 3NF decomposition সবসময় lossless আর dependency-preserving করা যায়, BCNF-এ শেষেরটি সবসময় নয়। পর্ব ৩৭
ভ-২৪Normalization কখন ক্ষতিকর? (মাঝারি)
যখন পড়া-প্রধান কাজে প্রতিটি কোয়েরিতে অনেক টেবিলের join লাগে আর তা ধীর হয় — যেমন রিপোর্ট বা dashboard; তখন জেনে-বুঝে denormalization (একটি গণনা করা কলাম, materialized view বা warehouse-এর star schema). তবে আগে index আর কোয়েরি ঠিক করুন, আর redundant কপি মিলিয়ে রাখার উপায় (trigger, job) রাখুন। পর্ব ৩৮
ভ-২৫Lossless join decomposition কী, আর দুই ভাগের ক্ষেত্রে কীভাবে পরীক্ষা করবেন? (মাঝারি)
ভাঙা টেবিলগুলো natural join করলে হুবহু আসল টেবিল ফেরে — বেশি (spurious) সারি আসে না। R1, R2-তে ভাঙলে শর্ত: R1 ∩ R2 → R1 অথবা R1 ∩ R2 → R2, অর্থাৎ সাধারণ কলাম অন্তত এক পাশের key. পর্ব ৩৭
স্টোরেজ, index ও query processing (পর্ব ৩৯–৪৩)
ভ-২৬কেন index লেখাকে ধীর করে? (সহজ)
প্রতিটি index টেবিলের এক বা কয়েকটি কলামের একটি সাজানো কপি, আর DBMS প্রতিটি INSERT, DELETE আর indexed কলামের UPDATE-এ প্রতিটি index-ও বদলায় — গাছে নেমে leaf-এ লেখা, মাঝে মাঝে split, সাথে WAL record. পাঁচটি index মানে একটি সারি লিখতে ছয়টি কাঠামোয় লেখা। পর্ব ৪০
ভ-২৭Index থাকা সত্ত্বেও কখন DBMS তা ব্যবহার করে না? (মাঝারি)
যখন শর্ত টেবিলের বড় অংশ মেলায় (কম selectivity — তখন পুরো scan সস্তা); কলামে ফাংশন বসলে (WHERE lower(name) = …, যদি না expression index থাকে); LIKE '%abc'-এর মতো শুরুতে wildcard; composite index-এর প্রথম কলাম না থাকলে; বা টাইপ মেলাতে কলাম রূপান্তর লাগলে। EXPLAIN দেখে নিশ্চিত হন। পর্ব ৪১
ভ-২৮Covering index কী? (মাঝারি)
যে index-এ কোয়েরির দরকারি সব কলাম আছে, ফলে টেবিলের সারি আর পড়তে হয় না — index-only scan. যেমন (dept_id, cgpa)-এর index SELECT cgpa FROM students WHERE dept_id = 1-কে পুরোটা মেটায়। দাম: বড় index, লেখায় বাড়তি খরচ। পর্ব ৪১
ভ-২৯EXPLAIN কী দেখায়? (সহজ)
ভ-৩০Cost-based optimizer কীভাবে plan বেছে নেয়? (মাঝারি)
সমতুল্য অনেক plan (join-এর ক্রম, অ্যালগরিদম, index) তৈরি করে, statistics (সারির সংখ্যা, আলাদা মানের সংখ্যা, histogram) দিয়ে প্রতিটির I/O আর CPU খরচ অনুমান করে, আর সবচেয়ে সস্তাটি বাছে — join-এর ক্রমে প্রায়ই dynamic programming. পুরোনো statistics মানে ভুল অনুমান, তাই ANALYZE জরুরি। পর্ব ৪৩
Transaction ও recovery (পর্ব ৪৪–৪৮)
ভ-৩১Dirty read কী? (সহজ)
একটি transaction অন্য transaction-এর এমন লেখা পড়ে, যা এখনো commit হয়নি; পরে সেটি rollback হলে পাঠক এমন মান দেখেছে যা কখনো ছিলই না। READ COMMITTED ও তার ওপরের সব level এটি ঠেকায়। পর্ব ৪৭
ভ-৩২Deadlock কী, আর DBMS কীভাবে তা ভাঙে? (সহজ)
দুই বা বেশি transaction একে অপরের ধরে রাখা lock-এর জন্য চক্রাকারে অপেক্ষা করে — কেউ এগোতে পারে না। DBMS wait-for graph-এ চক্র খুঁজে একটিকে victim করে abort করে; অ্যাপকে সেই ত্রুটি ধরে transaction আবার চালাতে হয়। সব জায়গায় একই ক্রমে lock নিলে বেশিরভাগ deadlock হয়ই না। পর্ব ৪৬
ভ-৩৩MVCC-র সুবিধা কী? (মাঝারি)
MVCC-তে প্রতিটি বদল সারির নতুন version বানায়, আর প্রতিটি transaction নিজের snapshot-এর version পড়ে — তাই পাঠক লেখককে আটকায় না, লেখক পাঠককে না। দাম: পুরোনো version জমে, পরিষ্কার করতে হয় (PostgreSQL-এ VACUUM, InnoDB-তে undo log-এর purge). পর্ব ৪৭
ভ-৩৪Commit-এ পুরো data page না লিখে শুধু log লিখলে কেন চলে? (মাঝারি)
কারণ WAL-এর log record-এ বদলটি আছে: crash হলে log থেকে redo করে বদল ফেরানো যায়। log লেখা sequential আর ছোট, অথচ data page ছড়ানো জায়গায় — তাই commit দ্রুত, আর data page পরে সুবিধামতো লেখা হয়। শর্ত: page লেখার আগে তার log ডিস্কে। পর্ব ৪৮
ভ-৩৫Checkpoint কেন দরকার? (সহজ)
Checkpoint ছাড়া crash-এর পর পুরো log প্রথম থেকে পড়তে হতো। Checkpoint বদলানো page-গুলো ডিস্কে লেখে (বা কোনটি বাকি তা নোট করে) আর log-এ চিহ্ন রাখে — recovery সেখান থেকে শুরু হয়, আর তার আগের log পুরোনো হলে recycle বা archive করা যায়। পর্ব ৪৮
অ্যাপ, নিরাপত্তা, NoSQL ও বড় মাপ (পর্ব ৪৯–৬২)
ভ-৩৬Prepared statement কেন SQL injection ঠেকায়? (সহজ)
কারণ SQL-এর গঠন আগে আলাদাভাবে parse হয়, আর ব্যবহারকারীর মান পরে শুধু ডেটা হিসেবে বসে — উদ্ধৃতিচিহ্ন থাকলেও তা কোড হয় না। তবে টেবিল বা কলামের নাম placeholder-এ যায় না; সেখানে allow-list লাগে। পর্ব ৫১
ভ-৩৭Connection pool কেন লাগে? (সহজ)
প্রতিটি অনুরোধে নতুন ডেটাবেস সংযোগ খোলা ধীর (নেটওয়ার্ক, authentication, সার্ভারে নতুন process বা thread). Pool কয়েকটি সংযোগ খোলা রেখে ধার দেয় আর ফেরত নেয়; সাথে মোট সংযোগের সীমাও রাখে, যাতে ডেটাবেস ভারে ভেঙে না পড়ে। পর্ব ৪৯
ভ-৩৮ORM-এর N+1 query সমস্যা কী? (মাঝারি)
১০০টি অর্ডার আনতে একটি কোয়েরি, তারপর প্রতিটির গ্রাহক আনতে আলাদা ১০০টি — মোট ১০১টি, যেখানে একটি join বা দুটি কোয়েরিই যথেষ্ট। ORM-এর lazy loading থেকে আসে; সমাধান eager loading (join বা IN (…) দিয়ে একবারে) আর query log দেখা। পর্ব ৫০
ভ-৩৯Replication থাকলে কি backup লাগে? (সহজ)
লাগে। Replication হার্ডওয়্যার নষ্ট হলে সেবা চালু রাখে, কিন্তু ভুল করে চালানো DELETE বা ransomware-এর এনক্রিপশনও সাথে সাথে replica-তে পৌঁছায়। শুধু backup (আর PITR) দিয়েই অতীতের সঠিক অবস্থায় ফেরা যায় — আর backup নিয়মিত ফিরিয়ে পরীক্ষা করতে হয়। পর্ব ৫২
ভ-৪০CAP theorem এক বাক্যে বলুন। (মাঝারি)
Network partition হলে একটি distributed ডেটাবেসকে বেছে নিতে হয় — সব node-এ সর্বশেষ মান (consistency), না প্রতিটি অনুরোধের উত্তর (availability); partition না থাকলে দুটিই সম্ভব। পর্ব ৫৪
ভ-৪১কখন NoSQL বাছবেন না? (মাঝারি)
যখন ডেটা গভীরভাবে সম্পর্কিত আর ad hoc join লাগে, বহু সারি বা টেবিলজুড়ে কঠোর ACID দরকার (টাকা, মজুত), বা কোয়েরির ধরন আগে থেকে জানা নেই। “স্কেল লাগবে” ভেবে শুরুতেই NoSQL নেওয়া প্রায়ই অকারণ জটিলতা; একটি relational ডেটাবেস অনেক দূর পর্যন্ত স্কেল করে। পর্ব ৫৬
ভ-৪২বিশ্লেষণে columnar স্টোরেজ কেন দ্রুত? (মাঝারি)
OLAP কোয়েরি অনেক সারির অল্প কয়েকটি কলাম পড়ে; columnar-এ প্রতিটি কলাম আলাদা জায়গায়, তাই শুধু দরকারি কলাম ডিস্ক থেকে আসে, আর একই ধরনের মান পাশাপাশি থাকায় compression অনেক বেশি। কিন্তু একটি পুরো সারি লেখা বা পড়া ধীর — তাই OLTP-তে row store. পর্ব ৫৫
৯ · AI-কে কড়া পরীক্ষক বানান — আর তার উত্তর যাচাই করুন
AI চ্যাটবট প্রস্তুতিতে দারুণ সঙ্গী — যদি তাকে উত্তরদাতা না বানিয়ে পরীক্ষক বানান: নিজে উত্তর লিখে মার্ক-স্কিম ধরে নম্বর দিতে বলুন, আর তার follow-up প্রশ্নের উত্তর মুখে দিন। তবে DBMS-এ AI-এর আত্মবিশ্বাসী ভুল খুব সাধারণ: এমন SQL যা চলে কিন্তু NULL বা ডুপ্লিকেটে ভুল ফল দেয়, একটি candidate key বাদ, বা এক DBMS-এর আচরণকে সবার বলা।
একটি prompt, যা AI-কে পরীক্ষক বানায় আর নিজের হিসাব দেখাতে বাধ্য করে:
DBMS নিয়ে AI-এর উত্তরে যেসব ভুল প্রায়ই থাকে
| ভুল | ফল | কীভাবে ধরবেন |
|---|---|---|
| NOT IN-এর subquery-তে NULL ভুলে যাওয়া | ফাঁকা ফল (খ-০৩) | এডিটরে চালান; subquery-র কলামে NULL আছে কি না দেখুন |
| LEFT JOIN-এর পর ডান টেবিলের শর্ত WHERE-এ | LEFT কার্যত INNER, সারি হারায় (খ-১০) | ফলের সারি-সংখ্যা বাঁ টেবিলের সাথে মেলান |
| COUNT(*) দিয়ে “শূন্য” গোনা | ০-এর জায়গায় ১ (খ-০২) | যে group-এ মিল নেই, সেটি আলাদা করে দেখুন |
| LIMIT 1 দিয়ে “সর্বোচ্চ” | সমান মান হারায় (খ-০৮) | সমান মানের একটি সারি যোগ করে আবার চালান |
| একটি candidate key বাদ | prime attribute ভুল, normal form-এর রায় ভুল (গ-০৩) | প্রতিটি ছোট সেটের closure নিজে হিসাব করুন |
| “BCNF decomposition সব FD রাখে” | হারানো নিয়ম চোখ এড়ায় (গ-০৬) | প্রতিটি FD-র জন্য dependency preservation-এর পরীক্ষা চালান |
| R-R জোড়াকে conflict ধরা, edge-এর দিক উল্টো | ভুল cycle বা ভুল serial ক্রম (ঙ-০৩) | প্রতিটি edge-এর পেছনের দুটি অপারেশন লিখতে বলুন |
| Sort বা join খরচে ceiling বা convention বাদ | সংখ্যা কাছাকাছি কিন্তু ভুল (ঘ-০৪) | প্রতিটি pass-এর run-সংখ্যা আলাদা করে লিখতে বলুন |
| একটি DBMS-এর আচরণকে standard বলা | যেমন “REPEATABLE READ-এ phantom হয় না” — PostgreSQL-এ সত্য, standard-এ নয় | প্রশ্ন করুন: কোন DBMS, কোন version; ডকুমেন্টেশন মেলান |
AI-এর উত্তর মেনে নেওয়ার আগে — চেকলিস্ট
আরও গভীরে: AI-কে দিয়ে নিজের দুর্বল জায়গা খুঁজুন: এই পাতার একটি প্রশ্নের উত্তর লিখে AI-কে বলুন “আমার উত্তরের সবচেয়ে দুর্বল বাক্যটি কোনটি, আর একজন পরীক্ষক সেখান থেকে কী follow-up করবেন?” তারপর সেই follow-up-এর উত্তর এই পাতার এডিটরে বা হিসাবে যাচাই করুন। এতে মুখস্থ নয়, যুক্তির ফাঁক ধরা পড়ে — যা ভাইভায় সবচেয়ে কাজে লাগে।
নিজেকে যাচাই করুন
প্রথমে একটি ক্রম সাজানোর প্রশ্ন, তারপর লিখিত আর ভাইভার মূল তথ্য নিয়ে MCQ. ভুল হলে কারণসহ ব্যাখ্যা পাবেন।
ক্রমএকটি relation-কে BCNF-এ decompose করে যাচাই করার ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- Attribute closure দিয়ে সব candidate key বের করা
- এমন একটি non-trivial FD X → Y খোঁজা, যেখানে X superkey নয়
- X+ দিয়ে relation-কে X+ আর R − (X+ − X)-এ ভাগ করা
- প্রতিটি নতুন টেবিলে projected FD ধরে একই কাজ, যতক্ষণ নিয়ম-ভাঙা FD থাকে
- কোন FD হারাল, তা dependency preservation-এর পরীক্ষায় দেখা
R(A, B, C, D, E)-এ F = {A → BC, CD → E, B → D, E → A}. R-এর candidate key কোনগুলো?
- A, E, BC, CD
- শুধু A
- A আর E
- A, E, BD
DELETE আর TRUNCATE নিয়ে কোন কথাটি সাধারণভাবে সঠিক?
- TRUNCATE-এ WHERE দিয়ে কিছু সারি বাছা যায়, DELETE-এ যায় না
- TRUNCATE WHERE নেয় না আর সারি-প্রতি DELETE trigger চালায় না; DELETE দুটিই পারে
- TRUNCATE টেবিলের গঠনসহ সব মুছে দেয়
- TRUNCATE কোনো DBMS-এই rollback করা যায় না
departments টেবিলে dept_id 1, 2, 3, 4; students টেবিলের dept_id কলামে মান 1, 2, 3 আর একটি NULL. SELECT dept_id FROM departments WHERE dept_id NOT IN (SELECT dept_id FROM students); কয়টি সারি দেয়?
- একটি সারি — 4
- চারটি সারি
- কোনো সারি নয়
- ত্রুটি দেয়
SQL standard-এর READ COMMITTED isolation level-এ নিচের কোনটি ঘটতে পারে না?
- Non-repeatable read
- Phantom read
- Lost update
- Dirty read
Schedule: R1(A), R2(B), W2(A), W1(B). এটি কি conflict serializable?
- না — precedence graph-এ T1 → T2 আর T2 → T1, একটি cycle
- হ্যাঁ — T1 তারপর T2
- হ্যাঁ — T2 তারপর T1
- কোনো conflict নেই, তাই প্রশ্ন অর্থহীন
Wait-die নিয়মে T1 (timestamp 5) একটি item-এর lock চাইল, যা ধরে আছে T2 (timestamp 10). কী হবে?
- T2 abort হবে, T1 lock পাবে
- T1 অপেক্ষা করবে
- T1 abort হবে
- দুটিই abort হবে
১০,০০০ page-এর একটি ফাইল ১১টি buffer page দিয়ে external merge sort করলে মোট কয়টি pass লাগে (pass 0 সহ)?
- ২
- ৩
- ৪
- ৫
teaches(sid, subject, teacher)-এ FD: {sid, subject} → teacher আর teacher → subject. teacher → subject ধরে BCNF-এ ভাঙলে (teacher, subject) আর (sid, teacher). কী হারায়?
- Lossless join — join করলে বাড়তি সারি আসে
- teacher → subject
- BCNF — একটি টেবিল এখনো BCNF নয়
- {sid, subject} → teacher
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বে ব্যবহৃত সব শব্দ এখানে একসাথে:
মনে রাখুন
- কাঠামোয় নম্বর: সংজ্ঞা → ব্যাখ্যা → উদাহরণ (টেবিল বা SQL) → ছবি → সুবিধা ও সীমা; প্রতিটি অংশ মার্ক-স্কিমের একটি ঘর।
- SQL-এর চার ফাঁদ: NOT IN-এ NULL, LEFT JOIN-এর পর WHERE, COUNT(*) দিয়ে শূন্য, LIMIT 1 দিয়ে সর্বোচ্চ — প্রতিটি চালিয়ে যাচাই করুন।
- Normalization-এর ধাপ: closure দিয়ে সব candidate key → কোন FD কোন শর্ত ভাঙে → decomposition → lossless আর dependency preservation দুটিই যাচাই। 3NF দুটিই দেয়; BCNF lossless দেয়, সব FD নয়।
- সংখ্যার প্রশ্নে: নিয়ম আগে লিখুন (B+ tree-এর split, শেষ লেখা গোনা কি না), ceiling ভুলবেন না, একক page I/O.
- Transaction-এ: প্রতিটি conflict জোড়া ধরে precedence graph; 2PL serializable দেয়, deadlock নয় — wait-die আর wound-wait-এ অপেক্ষা একমুখী। ভাইভায় তিন বাক্য, জোরে ভাবা, টেবিল আঁকা আর সৎ “নিশ্চিত নই”.
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ৬৬ · SQL ইন্টারভিউর সমস্যা — প্যাটার্ন ধরে সমাধানপরবর্তী পর্বইন্টারভিউর ক্লাসিক SQL প্যাটার্ন, লাইভ এডিটরে।
- পর্ব ৬৩ · SQL output predictionএকই মডিউলকোয়েরির ফল হাতে বের করার অনুশীলন।
- পর্ব ৬৪ · MCQ প্রশ্নব্যাংক — DBMS আর SQLএকই মডিউলপুরো কোর্সের MCQ, ব্যাখ্যাসহ।
- পর্ব ৩৭ · BCNF, 4NF, 5NF আর decomposition-এর গুণফিরে দেখুনlossless join আর dependency preservation-এর পূর্ণ তত্ত্ব।
- ডেটাবেস (DBMS) ও SQL · কোর্স হোম৬৭টি পর্বপুরো কোর্সের রোডম্যাপ — ১০টি মডিউল।
- DSA · লিখিত ও ভাইভা প্রশ্নসম্পর্কিত কোর্সB-tree, hashing আর sorting-এর প্রমাণ ও মডেল উত্তর।