ডেটাবেস: SQL বনাম NoSQL (Databases: SQL vs NoSQL)
বড় চিত্র (The Big Picture)
প্রতিটি অ্যাপ্লিকেশনেরই ডেটা সংরক্ষণের জন্য কোনো না কোনো জায়গা প্রয়োজন হয়। আপনি কোন ডেটাবেস বেছে নিচ্ছেন তার ওপর সবকিছু নির্ভর করে — আপনার অ্যাপ কতো দ্রুত চলবে, এটি কতো ভালোভাবে স্কেল করবে এবং রাত ৩টায় কিছু নষ্ট হয়ে গেলে আপনি কতটা কষ্টে পড়বেন।
ডেটাবেসের প্রধান দুটি ধরণ হলো: SQL (রিলেশনাল) ডেটাবেস এবং NoSQL (নন-রিলেশনাল) ডেটাবেস। এটিকে আপনার জিনিসপত্র গুছিয়ে রাখার মতো ভাবতে পারেন: SQL হলো একটি সম্পূর্ণ গোছানো ফাইলিং কেবিনেট যেখানে প্রতিটি ফাইলের লেবেল বা নাম দেওয়া আছে। অন্যদিকে NoSQL হলো আলাদা আলাদা বিভিন্ন স্টোরেজ সলিউশনের একটি কালেকশন — রেন্ডম আইটেম রাখার একটা বাক্স, নথিপত্র রাখার একটা তাক, যোগাযোগের তথ্যের জন্য একটা রোলোডেক্স।
এদের মধ্যে কোনোটিই একটি আরেকটির চেয়ে "সেরা" নয়। তারা প্রত্যেকেই ভিন্ন ভিন্ন সমস্যার সমাধান করে। চলুন দুটোকেই বোঝার চেষ্টা করা যাক।
SQL / রিলেশনাল ডেটাবেস (SQL / Relational Databases)
SQL ডেটাবেসগুলো (MySQL, PostgreSQL, Oracle, SQL Server) অনেকটা স্প্রেডশিটের মতো রো এবং কলাম বিশিষ্ট টেবিল (Tables)-এ ডেটা রাখে। প্রতিটি টেবিলের নিজস্ব একটি স্কিমা (Schema) থাকে যা বলে দেয় যে টেবিলটিতে কী কী কলাম থাকবে এবং তারা কোন ধরনের ডেটা ধারণ করবে।
একটি users টেবিলে কিছু কলাম থাকতে পারে: id (int), name (varchar), email (varchar), created_at (timestamp)। প্রতিটি রো (Row) ঠিক এই গঠনগত নিয়ম অনুসরণ করে। ইমেইল ছাড়া একটা ব্যবহারকারী অ্যাড করতে চান? ডেটাবেস সেটা হতে দেবে না।
টেবিলগুলোর একে অন্যের সাথে ফরেন কী-এর (foreign keys) সাহায্যে সম্পর্ক থাকে। একটি posts টেবিলে user_id কলাম থাকে, যা users টেবিলের দিকে নির্দেশ করে। এ কারণেই এগুলোকে রিলেশনাল (relational) ডেটাবেস বলা হয় — এদের মূল ক্ষমতা হলো এই সম্পর্কগুলো।
নরমালাইজেশন (Normalization) হলো ডেটা সংগঠিত করার এমন এক প্রক্রিয়া, যা ডুপ্লিকেট ডেটা কমিয়ে দেয়। ব্যবহারকারীর প্রতিটি পোস্টের সাথে তার নাম স্টোর করার বদলে, আপনি সেখানে user_id সেভ করেন এবং যখন দুটো ডাটারই দরকার পরে, তখন আপনি টেবিলগুলোকে JOIN করেন। কম ডুপ্লিকেশন = কম অসঙ্গতি।
ACID প্রপার্টিজ (ACID Properties)
SQL ডেটাবেসগুলো ACID প্রপার্টির নিশ্চয়তা দেয় — এটি আপনার ডেটার আচরণ সম্পর্কে চারটি গ্যারান্টি দেয়:
- অ্যাটোমিসিটি (Atomicity) — একটি ট্রানজেকশনে হয় সম্পূর্ণ কাজ হবে, না হয় কিছুই হবে কেন্দ্রীয় না। আপনি যদি আনিকার অ্যাকাউন্ট থেকে রাফির কাছে $১০০ ট্রান্সফার করেন, তবে ডেবিট এবং ক্রেডিট দুটো কাজই হবে, অথবা কিছুই হবে না। কোনো "টাকা গায়েব" টাইপ বাগ থাকতে পারে না।
- কনসিস্টেন্সি (Consistency) — ডেটাবেস একটি ভ্যালিড অবস্থা থেকে আরেকটি ভ্যালিড অবস্থায় যায়। সমস্ত শর্ত (constraints, foreign keys) শক্তভাবে মানা হয়। এমন কোনো পোস্ট থাকতে পারে না যা এমন কোনো ব্যবহারকারীকে নির্দেশ করে যার অস্তিত্বই নেই।
- আইসোলেশন (Isolation) — সমসাময়িক ট্রানজেকশনগুলো একে অপরকে বাধা দেয় না। যদি দুজন মানুষ একই সাথে কনসার্টের শেষ টিকিটটি কিনতে যায়, তবে কেবল একজন তা পাবে।
- ডিউরেবিলিটি (Durability) — কোনো ট্রানজেকশন একবার সম্পন্ন (commit) হলে, তা চিরস্থায়ী হয়ে যায়। এক মিলি-সেকেন্ড পর সার্ভারের সংযোগ বিচ্ছিন্ন হয়ে গেলেও আপনার ডেটা নিরাপদ।
ফিন্যান্সিয়াল সিস্টেম, ই-কমার্স এবং যে কোন সিস্টেম যেখানে গতির চেয়ে তথ্যের নিশ্চয়তা বেশি গুরুত্বপূর্ণ, সেগুলোর জন্য ACID অপরিহার্য।
SQL বনাম NoSQL ডেটা মডেলিং
NoSQL ডেটাবেসের প্রকারভেদ (NoSQL Database Types)
NoSQL হলো সেই সব ডেটাবেস যা প্রথাগত রিলেশনাল ডেটাবেসের বাইরে। এগুলোর প্রধান চারটি ধরণ আছে:
১. কী-ভ্যালু স্টোর (Key-Value Stores) (Redis, DynamoDB, Memcached)
- এটি সবচেয়ে সহজ একটি মডেল। এটি আক্ষরিক অর্থেই একটি ডিকশনারি: কী (key) ইনপুট দিন, ভ্যালু ফিয়ে পান।
- দারুন দ্রুত। ক্যাশিং (caching), সেশন স্টোরেজ (session storage) বা ইউজার প্রেফারেন্সের জন্য এটি পারফেক্ট।
- সীমিত খোঁজার সুবিধা — আপনি কেবল কী-এর মাধ্যমে খুঁজতে পারেন।
২. ডকুমেন্ট স্টোর (Document Stores) (MongoDB, CouchDB, Firestore)
- এটি JSON-লাইক ডকুমেন্টের মতো ডেটা স্টোর করে। একেকটি ডকুমেন্টের স্ট্রাকচার ভিন্ন হতে পারে।
- কন্টেন্ট ম্যানেজমেন্ট, ইউজারের প্রোফাইল, ক্যাটালগ ইত্যাদির জন্য এটি খুব দারুণ কাজ করে।
- SQL-এর চেয়ে অনেক বেশি নমনীয় — কোনো স্কিমা মাইগ্রেশন ছাড়াই যেকোনো সময় এতে ফিল্ড যোগ করতে পারবেন।
৩. কলাম-ফ্যামিলি স্টোর (Column-Family Stores) (Cassandra, HBase, ScyllaDB)
- রো-র পরিবর্তে কলামগুলোতে ডেটা সঞ্চয় করে। বড় বড় ডেটাসেটে অ্যানালিটিকাল প্রশ্নের (Analytical queries) জন্য এটি ভালো।
- দুর্দান্ত রাইট থ্রুপুট (Write throughput)। খুব স্বতস্ফুর্তভাবে হরাইজন্টালি স্কেল করতে পারে।
- টাইম-সিরিজ (Time-series) ডাটা, ইন্টারনেট অফ থিংস (IoT), ইভেন্ট লগিংয়ের জন্য ব্যবহৃত হয়।
৪. গ্রাফ ডেটাবেস (Graph Databases) (Neo4j, Amazon Neptune, ArangoDB)
- নোড এবং এজগুলোর (nodes and edges) মতো ডেটা সঞ্চয় করে। পরস্পরের সাথে সম্পর্কযুক্ত ডেটার জন্য এটি খুব কাজের।
- সোশ্যাল নেটওয়ার্ক (কে কাকে ফলো করে), রেকমেন্ডেশন ইঞ্জিন, ফ্রড ডিটেকশনের জন্য ব্যবহৃত হয়।
- "বন্ধুদের বন্ধুদের খুঁজে বের করো"-র মতো প্রশ্নগুলো এর মাধ্যমে খুব সহজেই এবং দ্রুততার সাথে উত্তর করা সম্ভব।
শার্ডিং (Sharding): ডেটাগুলোকে বিভিন্ন সার্ভারে ভাগ করে দেওয়া
যখন আপনার ডেটাবেস সাইজে অনেক বড় হয়ে যায় এবং একটি সার্ভারে কুলিয়ে উঠতে পারে, তখন আপনাকে একে শার্ড (shard) করতে হয় — অর্থাৎ ডেটাগুলোকে একাধিক সার্ভারের মধ্যে ভাগ করতে হয়। প্রতিটি সার্ভার সম্পূর্ণ ডেটাবেসের কিছু অংশ (শার্ড/shard) ধারণ করে থাকে।
শার্ডিংয়ের সাধারণ পদ্ধতিগুলো হলো:
- রেঞ্জ-বেসড (Range-based): A-M পর্যন্ত ইউজাররা শার্ড ১-এ, N-Z পর্যন্ত ইউজাররা শার্ড ২-এ। এটা সহজ হলেও এর একটি সমস্যা হলো এটি ডেটার পরিমাণকে অসমভাবে ভাগ (hotspots) করতে পারে।
- হ্যাশ-বেসড (Hash-based): কোনো কী (Key)-কে হ্যাশ করুন এবং (যেমন ইউজার আইডি) হ্যাশ করুন এবং মোট শার্ডের সংখ্যা দিয়ে মড (mod) করুন। এটি ডেটাকে সমানভাবে ভাগ করে, তবে নির্দিষ্ট একটি রেঞ্জে খোঁজার বিষয়টি এর ফলে অত্যন্ত কঠিন হয়ে দাঁড়ায়।
- জিওগ্রাফি-বেসড (Geography-based): ইউএসের ইউজাররা ইউএস শার্ডে, ইউরোপীয় ইউজাররা ইউরোপীয় শার্ডে। এটি আইনি সম্মতি (GDPR) এবং কম ল্যাটেন্সির জন্য দারুণ।
শার্ডিংয়ের কারণে সিস্টেমে নানা জটিলতাও যুক্ত হয়: আলাদা শার্ডগুলোতে কোয়েরি চালানো বেশ ব্যয়বহুল, এগুলোর ব্যালান্স রক্ষা করা বেশ কষ্টের এবং অনেক অপারেশন (যেমন একাধিক শার্ডের মধ্যে JOIN করা) প্রায় অসম্ভব হয়ে দাঁড়ায়। যে কারণে ডেটাবেস ইঞ্জিনিয়াররা যথাসম্ভব শার্ডিংয়ের বিষয়টিকে এড়ানোর চেষ্টা করেন এবং শুরুতে ভার্টিকাল স্কেলিং বা রিড রেপ্লিকার সাহায্যে বিষয়টির সমাধানের পথ খোঁজেন।
রেপ্লিকেশন (Replication)
রেপ্লিকেশন মানে আপনার ডেটার কপি একাধিক সার্ভারে সংরক্ষণ করা। এর দুটো প্রধান ধরন আছে:
লিডার-ফলোয়ার (Leader-Follower / Primary-Replica): একটি সার্ভার (লিডার) সব রাইট (Writes) হ্যান্ডেল করে। এটি এক বা একাধিক ফলোয়ার সার্ভারে ডেটা কপি করে পাঠায় আর সে সার্ভারগুলো শুধু রিড (Reads) হ্যান্ডেল করে। রিড হেভি কাজের জন্য এটি বেশ ভালো — আরও ফলোয়ার সার্ভার যুক্ত করে খুব সহজে বেশি বেশি রিড হ্যান্ডেল করা সম্ভব।
লিডার-লিডার (Leader-Leader / Multi-Master): একাধিক সার্ভার রাইট হ্যান্ডেল করতে পারে। এটি বেশ জটিল, কারণ আপনাকে রাইট কনফ্লিক্টগুলো (দুটি সার্ভার একই ডেটা একই সময়ে আপডেট করলে) সমাধান করতে হবে। যখন ডাটাকে বিভিন্ন রিজিয়নে লেখার প্রয়োজন পড়ে তখন এটি ব্যবহার করা হয়।
রেপ্লিকেশনের কিছু সুবিধা:
- হাই অ্যাভেলেবিলিটি (High availability) — যদি লিডার মারা যায়, তবে একজন ফলোয়ারকে লিডারের পদে নিয়ে আসা হয়।
- বেটার রিড পারফরমেন্স (Better read performance) — প্রচুর রেপ্লিকার মধ্যে রিডগুলোকে ভাগ করে দেওয়া হয়।
- জিওগ্রাফিক ডিস্ট্রিবিউশন (Geographic distribution) — কম লেটেন্সির জন্য ইউজারদের কাছাকাছি রেপ্লিকা রাখা যায়।
এর ট্রেড-অফ হলো রেপ্লিকেশন ল্যাগ (replication lag)। ফলোয়ার সার্ভারগুলো হয়তো লিডারের কয়েক মিলি-সেকেন্ড (বা সেকেন্ড) পিছনে থাকতে পারে। একজন ইউজার কোনো ডেটা লিখে অন্য একটি ফলোয়ার সার্ভার থেকে রিড করার চেষ্টা করলে সে পুরনো ডেটা দেখতে পারে। ক্যাপ থিওরেম লেসনে কনসিস্টেন্সি এবং অ্যাভেলেবিলিটির এই ট্রেড-অফ নিয়ে আমরা বিস্তারিত জানবো।
Key Metrics
ছোট কুইজ
পড়া চালিয়ে যান