আপনাকে একটা ছোট প্রশ্ন করি? মনে করুন আপনার এনআইডি (NID) কার্ডের নাম পরিবর্তন করা লাগবে, তখন কী কী ডকুমেন্ট লাগবে সেটা তো ধারণা করতে পারছেন? এর থেকেও বড় কথা, আপনি যে নামটা পরিবর্তন করলেন, এখন কিন্তু আপনার যত সরকারি নথিপত্র (সার্টিফিকেট, ড্রাইভিং লাইসেন্স ইত্যাদি) আছে সেগুলোতেও কিন্তু নাম পরিবর্তন করা লাগবে। না হলে কিন্তু ঝামেলা হবে। প্রথম দিকে একটু কঠিন লাগতে পারে কিন্তু একবার অভ্যস্ত হয়ে গেলে দেখবেন ডাটাবেজ নরমালাইজ করাটা অনেক সহজ মনে হচ্ছে।
আপনি যে নাম পরিবর্তন করবেন সেটাও সরকারি ডকুমেন্ট আর বাকি যেগুলোতে আপডেট করতে হবে, সেগুলোও কিন্তু সরকারি ডকুমেন্ট। এখন এক জায়গায় পরিবর্তন করার জন্য সব জায়গাতেই পরিবর্তন করতে হবে। এখানে অনেক সময় নষ্ট হবে। আর এই দেশের সরকারি অফিসের কাজ কেমন, সেটা যদি আপনি কোনো কাজ করার জন্য কোনোদিন সরকারি অফিসে যান তাহলে বুঝবেন।
এটা কিন্তু একটা সমস্যা, এখন এই সমস্যাটার কি সমাধান নাই? একটা সমাধান হতে পারে, যে একজায়গায় সম্পর্কিত তথ্য যেমন—নাম, ঠিকানা, ব্লাড গ্রুপ (এই তথ্যগুলো কিন্তু সব জায়গায় একই থাকে), এগুলো একটা সেন্ট্রাল জায়গায় থাকবে। সেখান থেকে সব ডকুমেন্ট-এ সরবরাহ হবে।
ওপরের যে সমস্যাটার কথা বললাম, এই সমস্যাটাকে বলে Data Redundancy। আর সমাধান যে বললাম সেটা হচ্ছে Normalization।
Database Normalization কী?
Database Normalization হলো রিলেশনাল ডাটাবেজে (Relational Database) তথ্য সুশৃঙ্খলভাবে সাজানোর একটি পদ্ধতি। এর মাধ্যমে বড় ও জটিল টেবিলগুলোকে ভেঙে ছোট এবং সম্পর্কযুক্ত টেবিলে রূপান্তর করা হয়। এর ফলে ডাটাবেজে Data Redundancy কমে এবং ডেটা নষ্ট হওয়ার ঝুঁকি দূর হয়।
Normalization-এর প্রধান উদ্দেশ্যগুলো হলো:
- Data Redundancy কমানো: একই তথ্য বারবার সংরক্ষণ করা বন্ধ করা। ওপরের উদাহরণ অনুযায়ী, সব জায়গায় একই information বারবার repeat হচ্ছে। একটা information update করার জন্য multiple জায়গায় information update করতে হচ্ছে। Normalization করলে এই redundancy চলে যাবে।
- Inconsistency দূর করা: Multiple জায়গায় data থাকলে, সব জায়গায় data update করতে হবে। এখন কোনো কারণে যদি কোনো একটা operation fail করে তাহলে কিন্তু data-র inconsistency (অসঙ্গতি) দেখা দিবে।
- Data Integrity নিশ্চিত করা: একটা information একজায়গায় থাকলে information ভুল হওয়ার সমস্যা থাকে না।
কেন Normalization দরকার?
নিচের (order table)-টা একটু খেয়াল করুন। এখানে খেয়াল করলে দেখবেন John Doe নামের একটা user ৩টা different product কিনেছে।
| order_id | customer_name | customer_email | product_name | product_price |
|---|---|---|---|---|
| 1 | John Doe | m@gmail.com | Laptop | 50000 |
| 2 | John Doe | m@gmail.com | Mouse | 500 |
| 3 | John Doe | m@gmail.com | Keyboard | 1200 |
এখানে normalization করলে এই problem-টা solve হবে। Normalization-এর অনেকগুলো step আছে: 1NF, 2NF, 3NF। নিচে এগুলো example-সহ বিস্তারিত আলোচনা করা হয়েছে।
First Normal Form (1NF): একটা cell, একটা value
মনে করুন, আপনি আপনার family-এর সাথে shopping করতে গেছেন, এখন আপনি ৩টা জিনিস কিনেছেন। আপনার ছোট ভাই কিনেছে ২টা জিনিস।
| user | items |
|---|---|
| Titu (you) | Laptop, Mouse, Keyboard |
| Riju (little bro) | Headphone, T-Shirt |
এখানে 2nd column খেয়াল করুন, এখানে Laptop, Mouse, Keyboard মোট ৩টা value store হচ্ছে। একটা value-এর বদলে একটা list রয়েছে। আর 1NF বলে, এই কাজটা করা যাবে না। একটা value-ই থাকবে, কোনো list থাকবে না। এর বদলে ৩টা row বানাতে হবে। যে কয়টা item থাকবে সেই কয়টা row থাকবে। এখন 1NF অনুযায়ী নিচের মতো হবে:
| user | items |
|---|---|
| Titu (you) | Laptop |
| Titu (you) | Mouse |
| Titu (you) | Keyboard |
| Riju (little bro) | Headphone |
| Riju (little bro) | T-Shirt |
Second Normal Form (2NF): সব column primary key-এর উপর dependent হতে হবে
| order_id (PK) | product_id (PK) | customer_name | product_name | quantity |
|---|---|---|---|---|
| 101 | P-1 | Rahim | Keyboard | 2 |
| 101 | P-2 | Rahim | Mouse | 1 |
| 102 | P-1 | Karim | Keyboard | 3 |
| 102 | P-3 | Karim | Monitor | 1 |
এখানে একটা জিনিস খেয়াল করুন, customer_name জানার জন্য শুধুমাত্র order_id-এর ওপরেই rely করে, order পেলেই name জানা যাবে। অর্থাৎ customer_name primary key-এর ওপর totally dependent না। Same জিনিসটা product_name-এর ক্ষেত্রেও প্রযোজ্য। এটা একটা problem। এটাকে বলে Partial Dependency।
আসলে problem-টা হচ্ছে এখানে Data Redundancy হচ্ছে। এটা হতে দেয়া যাবে না। আর তা যাতে না হয়, সেটাই হচ্ছে 2NF। শুদ্ধ ভাষায় বললে:
**প্রতিটি non-key column-কে পুরো primary key-এর উপর fully dependent হতে হবে — key-এর শুধু একটা অংশের উপর নয়।**
একটা table 2NF-এ থাকার শর্ত দুইটা:
- টেবিলটা আগে 1NF-এ থাকতে হবে (atomic values, no repeating groups)।
- Partial Dependencies দূর করা।
তবে এখানে একটা catch আছে। এই 2NF-টা তখনই valid হবে যখন কোনো table-এ composite primary key থাকে। Partial dependencies resolve করলেই 2NF form হয়ে যাবে। তবে কোনো table-এ যদি single primary key থাকে তাহলে সেখানে partial dependencies হওয়ার possibility থাকে না। সেটা automatically 2NF format-এই থাকে।
Example: একটা Order System
ধরা যাক আমরা order-এর line item একটা টেবিলে রাখছি। একটা order-এ একাধিক product থাকতে পারে, তাই key হলো (order_id, product_id) — composite।
#### ❌ 2NF Violation (খারাপ design)
order_items table
| order_id (PK) | product_id (PK) | customer_name | product_name | quantity |
|---|---|---|---|---|
| 101 | P-1 | Rahim | Keyboard | 2 |
| 101 | P-2 | Rahim | Mouse | 1 |
| 102 | P-1 | Karim | Keyboard | 3 |
| 102 | P-3 | Karim | Monitor | 1 |
এখন dependency-গুলো খেয়াল করুন:
customer_name→ শুধুorder_id-এর উপর depend করে। অর্থাৎ order_id জানলেই customer name জানা যাবে। আর এখানেorder_idএকটা partial key। এর জন্য এটা একটা partial dependency।product_name→ শুধুproduct_id-এর উপর depend করে। অর্থাৎ product_id জানলেই product name জানা যাবে। আর এখানেproduct_id-ও একটা partial key। এর জন্য এটাও একটা partial dependency।quantity→ এটা full dependency। কারণ একটা specific order-এ একটা specific product কতটা কিনেছে তা জানার জন্য সম্পূর্ণ key(order_id, product_id)লাগে।
এই design-এর সমস্যা কী?
- Data Redundancy: রহিম-এর নাম দুইবার লেখা, "Keyboard" নামটাও বারবার repeat হচ্ছে।
- Update Anomaly: রহিম তার নাম বদলালে একাধিক row update করতে হবে — একটা মিস হলেই data inconsistent।
- Insert Anomaly: নতুন একটা product (যেটা কেউ এখনো order করেনি) database-এ রাখতে পারবে না, কারণ
order_idছাড়া row insert হবে না। - Delete Anomaly: কোনো order-এর সব row delete করলে customer বা product-এর তথ্যও হারিয়ে যাবে।
✅ 2NF Solution (সঠিক design)
Solution একদম easy, partial dependencies-এর জন্য আলাদা dedicated table বানাতে হবে। সেখানে এই data-গুলো insert করে দিলেই হয়ে যাবে। এখন main table-এ redundancy completely remove হয়ে যাবে।
orders table — customer_name এখন order_id-এর সাথেই থাকছে
| order_id (PK) | customer_name |
|---|---|
| 101 | Rahim |
| 102 | Karim |
| product_id (PK) | product_name |
|---|---|
| P-1 | Keyboard |
| P-2 | Mouse |
| P-3 | Monitor |
| order_id (PK, FK) | product_id (PK, FK) | quantity |
|---|---|---|
| 101 | P-1 | 2 |
| 101 | P-2 | 1 |
| 102 | P-1 | 3 |
| 102 | P-3 | 1 |
- Rahim-এর নাম একবারই আছে — নাম বদলালে একটা জায়গায় update করলেই হবে।
- নতুন product order ছাড়াই
productstable-এ insert করা যাবে। - কোনো order delete করলেও customer আর product info নিরাপদ থাকবে।
order_items-এর প্রতিটা column (এখানে শুধুquantity) পুরো key(order_id, product_id)-এর উপর fully dependent। ✅
Third Normal Form (3NF): Transitive Dependency বাদ দাও
বড় করে বলে বোঝানো যাক। মনে করুন key → A আর A → B। তাহলে ঘুরে ফিরে key → B হয়, কিন্তু B actually key-এর ওপর directly depend করছে না — সে depend করছে A-এর ওপর, যেটা নিজেও একটা non-key column। এই indirect dependency-টাই হচ্ছে transitive dependency।
শুদ্ধ ভাষায় বললে:
**কোনো non-key column যেন আরেকটা non-key column-এর উপর dependent না হয় — প্রতিটা non-key column directly primary key-এর উপর depend করবে।**
একটা table 3NF-এ থাকার condition দুইটা:
- Table-টা আগে 2NF-এ থাকতে হবে (no partial dependency)।
- কোনো transitive dependency থাকবে না — অর্থাৎ
key → A → Bএমন chain চলবে না, যেখানেBnon-key হয়ে আরেকটা non-keyA-এর ওপর ঝুলে আছে।
Example: একটা Employee System
| emp_id (PK) | emp_name | dept_id | dept_name | dept_location |
|---|---|---|---|---|
| E-01 | Rahim | D-1 | Engineering | Dhaka |
| E-02 | Karim | D-1 | Engineering | Dhaka |
| E-03 | Sumi | D-2 | Marketing | Chittagong |
| E-04 | Jamal | D-2 | Marketing | Chittagong |
emp_id→dept_id: একজন employee একটা specific department-এ থাকে। ✅ directly depend করছে।dept_id→dept_name,dept_location: একটা department-এর name আর location ঠিক করে দেয়dept_id, employee দিয়ে তাতে কিছু আসে যায় না।- ফলে
emp_id→dept_id→dept_name— অর্থাৎdept_nameআরdept_locationtransitively dependent। 🚨 এরা একটা non-key column (dept_id)-এর ওপর ঝুলে আছে, key-এর ওপর directly না।
- Data Redundancy: "Engineering, Dhaka" বারবার repeat হচ্ছে — যত employee সেই department-এ, ততবার।
- Update Anomaly: Engineering department Dhaka থেকে Khulna-তে shift করলে একাধিক row update করতে হবে। একটা miss হলে এই same department-এর দুইরকমের location দেখাবে — inconsistent।
- Insert Anomaly: নতুন একটা department (যেখানে এখনো কোনো employee নেই) database-এ রাখা যাবে না, কারণ
emp_idছাড়া row insert হয় না। - Delete Anomaly: কোনো department-এর শেষ employee-কে delete করলে সেই department-এর info-ও (name, location) হারিয়ে যাবে।
Solution একদম easy, transitively dependent column-গুলোকে আলাদা dedicated table-এ সরাতে হবে। যে non-key column (dept_id) এদেরকে determine করছে, সেটাকে নতুন table-এর primary key বানাতে হবে। এখন main table-এ redundancy completely remove হয়ে যাবে।
departments table — dept_name আর dept_location এখন তাদের actual determinant dept_id-এর সাথে
| dept_id (PK) | dept_name | dept_location |
|---|---|---|
| D-1 | Engineering | Dhaka |
| D-2 | Marketing | Chittagong |
| emp_id (PK) | emp_name | dept_id (FK) |
|---|---|---|
| E-01 | Rahim | D-1 |
| E-02 | Karim | D-1 |
| E-03 | Sumi | D-2 |
| E-04 | Jamal | D-2 |
- "Engineering, Dhaka" একবারই আছে — department shift করলে একটা জায়গায় update করলেই হবে।
- নতুন department employee ছাড়াই
departmentstable-এ insert করা যাবে। - শেষ employee delete করলেও department-এর info নিরাপদ থাকবে।
employees-এর প্রতিটা non-key column (emp_name,dept_id) directlyemp_id-এর ওপর depend করছে — কোনো ঘুরপথ নেই। ✅
Over-Normalization: যেখানে ক্যাচালটা লাগে!
সব কিছু normalize করলেই কি ভালো? একদমই না! বেশি normalization মানে বেশি JOIN। বেশি JOIN মানে slow query। একটা report generate করতে ১০টা table JOIN করতে হচ্ছে। এটা performance nightmare।
অনেক সময় usage ও requirement-এর ওপর নির্ভর করে intentionally Denormalization করা হয়ে থাকে যাতে সিস্টেমে unnecessary operations কমানো যায়। এ ছাড়াও read-heavy সিস্টেমেও intentionally controlled denormalization করা হয়ে থাকে।
বটম লাইন
একটা জিনিস খেয়াল করবেন, আপনি যদি অনেক দিন ধরে backend engineer হিসেবে কাজ করেন তাহলে আপনি ওপরে যা যা বললাম তার বেশির ভাগ জিনিসই আপনি না জেনেই apply করে ফেলেছেন। আসলে আপনি ডাটাবেসটা properly design করলে আপনার এই normalization-এর formality নিয়ে প্যারা খেতে হবে না। আপনার logic-ই আপনাকে ডাটাবেস normalize করতে help করবে।
আর সত্য বলতে আমি নিজেই এই রকম সিচুয়েশনে পড়েছি। এই database normalization নিয়ে পড়াশোনা করার আগেই এই প্রবলেম সলিউশন করেছি।
আপনি কখনো ডাটাবেস normalize না করার জন্য প্যারা খেয়েছেন? অবশ্যই শেয়ার করুন! 👇