রিলেশনাল ডাটাবেস কী?
রিলেশনাল ডাটাবেস (RDBMS) হলো একটি ডাটাবেস ম্যানেজমেন্ট সিস্টেম যেখানে ডাটা টেবিল আকারে সংরক্ষণ করা হয় এবং টেবিলগুলোর মধ্যে রিলেশন (সম্পর্ক) থাকে। প্রতিটি টেবিলে রো (সারি/রেকর্ড) এবং কলাম (ফিল্ড/অ্যাট্রিবিউট) থাকে।
সহজ ভাষায়:
একটি এক্সেল শিটের মতো, কিন্তু অনেক বেশি শক্তিশালী। একাধিক শিটের মধ্যে সম্পর্ক তৈরি করা যায় এবং খুব জটিল প্রশ্নের উত্তর দেওয়া যায়।
┌─────────────────┐ ┌─────────────────┐
│ ইউজার টেবিল │ │ অর্ডার টেবিল │
├─────┬─────┬─────┤ ├─────┬─────┬─────┤
│user_id│ নাম │ শহর │ │order_id│user_id│ প্রোডাক্ট │
├─────┼─────┼─────┤ ├─────┼─────┼─────┤
│ 1 │ রহিম│ ঢাকা │ │ 101 │ 1 │ ল্যাপটপ │
│ 2 │ করিম│ চট্টগ্রাম│ │ 102 │ 1 │ মাউস │
│ 3 │ জব্বার│খুলনা │ │ 103 │ 2 │ কিবোর্ড │
└─────┴─────┴─────┘ └─────┴─────┴─────┘
↑
(user_id = foreign key)
কেন রিলেশনাল ডাটাবেস?
| সুবিধা | ব্যাখ্যা |
|---|---|
| এসিড কমপ্লায়েন্স | Atomicity, Consistency, Isolation, Durability – ডাটা ইন্টিগ্রিটি নিশ্চিত করে |
| জটিল কুয়েরি | SQL দিয়ে জয়েন, সাবকুয়েরি, এগ্রিগেশন করা যায় |
| রেফারেন্সিয়াল ইন্টিগ্রিটি | ফরেন কী দিয়ে ডাটার মধ্যে সম্পর্ক বজায় রাখে |
| স্ট্যান্ডার্ডাইজেশন | SQL প্রায় সব জায়গায় একই রকম |
| মাচুরিটি | ৪০+ বছর ধরে গবেষণা ও অপটিমাইজেশন |
মূল ধারণাসমূহ
১. টেবিল ও স্কিমা
-- স্কিমা ডেফিনেশন (টেবিলের গঠন)
CREATE TABLE users (
user_id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
২. প্রাইমারি কী (Primary Key)
প্রতিটি রোকে ইউনিকভাবে চিহ্নিত করে।
প্রাইমারি কী হতে হবে:
✅ ইউনিক – কোনো ডুপ্লিকেট নেই
✅ নট নাল – সব রোতে অবশ্যই মান থাকতে হবে
✅ ইমিউটেবল – পরিবর্তন করা উচিত নয়
৩. ফরেন কী (Foreign Key)
দুটি টেবিলের মধ্যে সম্পর্ক তৈরি করে।
CREATE TABLE orders (
order_id INT PRIMARY KEY,
user_id INT,
FOREIGN KEY (user_id) REFERENCES users(user_id)
);
৪. ইনডেক্স (Index)
ডাটা খোঁজা দ্রুত করতে সাহায্য করে।
ইনডেক্স ছাড়া: পুরো টেবিল স্ক্যান → O(n)
ইনডেক্স দিয়ে: B-Tree অনুসন্ধান → O(log n)
উদাহরণ: ১০ মিলিয়ন রো-র টেবিলে
ইনডেক্স ছাড়া খুঁজতে → ~১০ সেকেন্ড
ইনডেক্স দিয়ে → ~০.০১ সেকেন্ড
CREATE INDEX idx_users_email ON users(email);
নরমালাইজেশন (Normalization)
ডাটা রিডান্ডেন্সি কমানোর প্রক্রিয়া।
নরমাল ফর্মসমূহ
| ফর্ম | নিয়ম | উদাহরণ |
|---|---|---|
| ১এনএফ | প্রতিটি সেলে একটি মান থাকবে | ❌ "মাউস,কিবোর্ড" → ✅ আলাদা রো |
| ২এনএফ | পার্শিয়াল ডিপেন্ডেন্সি থাকবে না (কম্পোজিট প্রাইমারি কী-র জন্য) | অর্ডার টেবিলে user_id থেকে user_name না রাখা |
| ৩এনএফ | ট্রানজিটিভ ডিপেন্ডেন্সি থাকবে না | user table-এ zipcode থেকে city বের করা যায় না |
ডিনরমালাইজেশন কখন করবেন?
| কখন | কেন |
|---|---|
| পড়ার পারফরম্যান্স বাড়াতে | জয়েন কমানোর জন্য |
| রিপোর্টিং/অ্যানালিটিক্সে | অনেক জয়েন ধীর করে দেয় |
| ক্যাশিং হিসেবে | ডাটা ফ্রিকোয়েন্টলি পড়া হয় |
এসিড প্রপার্টিজ (ACID)
| প্রপার্টি | ব্যাখ্যা | বাস্তব উদাহরণ |
|---|---|---|
| Atomicity | সব অপারেশন সফল না হলে পুরো ট্রানজেকশন বাতিল | ব্যাংক ট্রান্সফার – টাকা কাটা ও যোগ করা দুটোই হবে নয়তো কিছুই হবে না |
| Consistency | ট্রানজেকশনের আগে-পরে ডাটাবেস কনসিস্টেন্ট থাকে | প্রাইমারি কী ইউনিক থাকবেই |
| Isolation | একসাথে চলা ট্রানজেকশন একে অপরকে প্রভাবিত করবে না | দুজন একই সময়ে শেষ আসন বুক করার চেষ্টা – একজন পাবে |
| Durability | কমিট করা ডাটা হারাবে না (ডিস্কে সেভ) | বিদ্যুৎ চলে গেলেও কমিট করা লেনদেন থাকবে |
আইসোলেশন লেভেল (Isolation Levels)
| লেভেল | ডার্টি রিড | নন-রিপিটেবল রিড | ফ্যান্টম রিড | ফোর লকিং |
|---|---|---|---|---|
| READ UNCOMMITTED | সম্ভব | সম্ভব | সম্ভব | না |
| READ COMMITTED | অসম্ভব | সম্ভব | সম্ভব | না |
| REPEATABLE READ | অসম্ভব | অসম্ভব | সম্ভব (MySQL না) | না |
| SERIALIZABLE | অসম্ভব | অসম্ভব | অসম্ভব | হ্যাঁ |
-- লেভেল সেট করা
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
SELECT balance FROM accounts WHERE user_id = 1;
-- অন্য ট্রানজেকশন user_id 1 এর ব্যালেন্স পরিবর্তন করতে পারবে
COMMIT;
জনপ্রিয় রিলেশনাল ডাটাবেস
| ডাটাবেস | টাইপ | স্ট্রং পয়েন্ট | ব্যবহার |
|---|---|---|---|
| PostgreSQL | ওপেন সোর্স | JSON সাপোর্ট, এক্সটেনসিবল | সাধারণ উদ্দেশ্য |
| MySQL | ওপেন সোর্স | দ্রুত রিড, জনপ্রিয় | ওয়েব অ্যাপ |
| SQLite | এম্বেডেড | লাইটওয়েট, কোনো সার্ভার নেই | মোবাইল, ব্রাউজার |
| Microsoft SQL Server | কমার্শিয়াল | BI টুল, .NET ইন্টিগ্রেশন | এন্টারপ্রাইজ |
| Oracle | কমার্শিয়াল | পার্টিশনিং (বিল্ট-ইন) | ব্যাংক, মিশন ক্রিটিক্যাল |
| Amazon Aurora | ক্লাউড | ৫× MySQL গতি, ৩× PostgreSQL গতি | AWS সার্ভিস |
জয়েন (JOIN) এর প্রকারভেদ
INNER JOIN: শুধু ম্যাচিং রো
LEFT JOIN: সব বাম টেবিল + ম্যাচিং ডান
RIGHT JOIN: সব ডান টেবিল + ম্যাচিং বাম
FULL OUTER: সব রো (উভয় টেবিল)
CROSS JOIN: কার্টেসিয়ান প্রোডাক্ট
-- INNER JOIN উদাহরণ
SELECT users.name, orders.product
FROM users
INNER JOIN orders ON users.user_id = orders.user_id;
-- একাধিক টেবিল জয়েন
SELECT u.name, o.product, p.price
FROM users u
JOIN orders o ON u.user_id = o.user_id
JOIN products p ON o.product_id = p.product_id
WHERE o.order_date > '2024-01-01';
রিলেশনাল বনাম নোএসকিউএল ডাটাবেস
| ফ্যাক্টর | রিলেশনাল (SQL) | নোএসকিউএল (NoSQL) |
|---|---|---|
| ডাটা মডেল | টেবিল (স্ট্রাকচার্ড) | ডকুমেন্ট, কী-ভ্যালু, গ্রাফ |
| স্কিমা | ফিক্সড (মাইগ্রেশন দরকার) | ফ্লেক্সিবল |
| স্কেলিং | ভার্টিক্যাল (উপরের দিকে) | হরাইজন্টাল (পাশের দিকে) |
| জয়েন | শক্তিশালী | দুর্বল বা নেই |
| এসিডি | পুরো সাপোর্ট | অনেকের নেই |
| ইউজ কেস | ট্রানজেকশন, রিপোর্ট | ক্যাশ, লগ, রিয়েল-টাইম |
| পরিণততা | খুব পরিণত (৪০+ বছর) | আধুনিক (১০+ বছর) |
কুয়েরি অপটিমাইজেশন টিপস
১. সিলেক্ট * ব্যবহার করবেন না
❌ SELECT * FROM users WHERE city = 'Dhaka';
✅ SELECT user_id, name FROM users WHERE city = 'Dhaka';
২. ইনডেক্স ব্যবহার করুন, কিন্তু অতিরিক্ত নয়
-- বারবার WHERE এ ব্যবহার হয় এমন কলামে ইনডেক্স
CREATE INDEX idx_users_city ON users(city);
-- কিন্তু ইনডেক্স বেশি হলে ইনসার্ট/আপডেট ধীর হয়
৩. কুয়েরি প্ল্যান এক্সপ্লেইন করুন
EXPLAIN SELECT * FROM users WHERE email = 'rahim@example.com';
-- দেখায় ইনডেক্স ব্যবহার করছে কিনা
৪. জয়েনের অর্ডার
- ছোট টেবিল আগে, বড় টেবিল পরে
- ইনডেক্সড কলামে জয়েন করুন
৫. ব্যাচ প্রসেসিং
❌ ১০০০ বার লুপ চালিয়ে UPDATE
✅ UPDATE users SET status = 'active'
WHERE last_login > '2024-01-01' LIMIT 1000;
কখন রিলেশনাল ডাটাবেস ব্যবহার করবেন?
করবেন:
- ব্যাংকিং, ই-কমার্স (ট্রানজেকশন জরুরি)
- রিপোর্টিং, BI (জটিল কুয়েরি লাগে)
- যেখানে ডাটার গঠন পরিষ্কার ও স্টেবল
- ডাটা ইন্টিগ্রিটি খুব গুরুত্বপূর্ণ
- শত শত টেরাবাইটের কম ডাটা
করবেন না:
- খুব বড় ডাটা (পেটাবাইট) → ডাটা ওয়্যারহাউস লাগে
- লেখা অনেক বেশি (মিলিয়ন/সেকেন্ড) → NoSQL ভালো
- ডাটার ধরন প্রায়ই বদলায় → স্কিমালেস NoSQL
- ফুল টেক্সট সার্চ দরকার → Elastisearch ভালো
সাধারণ সমস্যা ও সমাধান
| সমস্যা | কারণ | সমাধান |
|---|---|---|
| ধীর কুয়েরি | ইনডেক্স নেই, পুরো টেবিল স্ক্যান | EXPLAIN করে দেখুন, ইনডেক্স যোগ করুন |
| ডেডলক | দুই ট্রানজেকশন একে অপরের জন্য অপেক্ষা | লকের অর্ডার ঠিক করুন, Retry লজিক যোগ করুন |
| কানেকশন লিক | কানেকশন বন্ধ করা হয়নি | কানেকশন পুল ব্যবহার করুন, defer/finally-এ ক্লোজ করুন |
| ব্লোটেড টেবিল | ডিলিট হলেও জায়গা ফেরত যায় না | VACUUM (PostgreSQL) বা OPTIMIZE (MySQL) চালান |
চিটশিট: দরকারি SQL কমান্ড
-- ক্রিয়েট
CREATE DATABASE mydb;
CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(50));
-- ইনসার্ট
INSERT INTO users (id, name) VALUES (1, 'রহিম');
INSERT INTO users (id, name) VALUES (2, 'করিম'), (3, 'জব্বার');
-- সিলেক্ট
SELECT * FROM users WHERE id = 1;
SELECT COUNT(*) FROM users;
-- আপডেট
UPDATE users SET name = 'রহিমুদ্দিন' WHERE id = 1;
-- ডিলিট
DELETE FROM users WHERE id = 3;
-- এগ্রিগেশন
SELECT city, COUNT(*) FROM users GROUP BY city;
SELECT city, AVG(age) FROM users GROUP BY city HAVING AVG(age) > 25;
-- সাবকুয়েরি
SELECT name FROM users
WHERE user_id IN (SELECT user_id FROM orders WHERE amount > 1000);