Relational আর key-value-র আসল পার্থক্য কোন প্রশ্নটা করা যায় তাতে, partition key-র একমুখী সিদ্ধান্ত, schema না থাকা কী কেনে আর কী খরচ করায়, capacity-র দুটো মডেল, scan আর query-র দামের ফারাক, আর শেষে একটা সম্পূর্ণ serverless pipeline — কোনো সার্ভার ছাড়াই।
পর্ব ১৬-এ আমরা একটা টেবিল বানিয়েছি আর তাতে লিখেছি, কিন্তু টেবিলটা কী সেটা নিয়ে কথা বলিনি। এবার সেটা।
DynamoDB একটা key-value ডেটাবেস — আর "NoSQL" শব্দটা এটাকে যেভাবে বোঝানো হয়, সেটা সাধারণত ভুল। "SQL নেই" একটা অনুপস্থিতির বর্ণনা; আসল পার্থক্যটা উপস্থিতির দিকে:
একটা relational ডেটাবেসে তুমি প্রায় যেকোনো প্রশ্ন করতে পারো। একটা key-value ডেটাবেসে তুমি যে প্রশ্নগুলোর জন্য নকশা করেছ, সেগুলোই করতে পারো।
এটা শুনতে একটা সীমাবদ্ধতা মনে হয়, আর সেটাই — কিন্তু সেই সীমাবদ্ধতাই দামটা দেয়। দেখা যাক কীভাবে।
Relational (PostgreSQL, MySQL):
SELECT u.name, COUNT(o.id) FROM users u JOIN orders o ON o.user_id = u.id WHERE o.created_at > '2026-01-01' GROUP BY u.name ORDER BY 2 DESC;
এই প্রশ্নটা আগে ভাবার দরকার ছিল না। টেবিল দুটো বানানোর সময় কেউ জানত না এই প্রশ্নটা আসবে, আর তবুও এটা কাজ করে। ডেটাবেস দরকারমতো জুড়ে নেয়, ছেঁকে নেয়, গুনে নেয়।
দামটা: ওই নমনীয়তার জন্য ডেটাবেসটাকে কাজ করতে হয় — আর ডেটা বড় হলে ওই কাজটা একটা সীমায় পৌঁছায়। একটা বড় JOIN একটা বড় টেবিলে ধীর হয়, আর সমাধান সাধারণত একটা বড় মেশিন।
Key-value (DynamoDB):
table.get_item(Key={"event_id": "evt-0a1b2c3d"})এটা সবসময় দ্রুত — এক মিলিসেকেন্ডের কাছাকাছি, আর টেবিলে দশটা আইটেম থাকলেও, দশ কোটি থাকলেও একই গতি।
কারণটা সরল: DynamoDB key-টা থেকে হিসাব করে বের করে ডেটাটা কোন physical partition-এ আছে, আর সোজা সেখানে যায়। কোনো খোঁজা নেই, তাই আকারের সাথে কোনো সম্পর্ক নেই।
দামটা: ওই একই প্রশ্নটাই সে ভালো পারে। "যেসব event-এর source lambda আর যারা গত সপ্তাহে হয়েছে" — এর জন্য কোনো দ্রুত পথ নেই, যদি তুমি আগে থেকে সেই পথটা তৈরি না করো।
তাহলে কখন কোনটা — আর এটা একটা ব্যবহারিক তালিকা:
আর একটা সৎ কথা, যেটা সাধারণত বলা হয় না: বেশিরভাগ অ্যাপ্লিকেশনের জন্য relational-ই সঠিক ডিফল্ট।
DynamoDB উজ্জ্বল হয় একটা নির্দিষ্ট আকৃতির কাজে — অনেক লেখা, জানা key, সরল প্রশ্ন। সেই আকৃতি না হলে ওটা বেছে নেওয়া মানে নিজের উপরে একটা সীমাবদ্ধতা চাপানো আর কোনো সুবিধা না পাওয়া।
তবে serverless-এ DynamoDB-র একটা আলাদা যুক্তি আছে, আর সেটা গতির নয়: সংযোগ। একটা relational ডেটাবেসে প্রতিটা ক্লায়েন্টকে একটা সংযোগ খুলতে হয়, আর Lambda একসাথে হাজারটা কপি চালাতে পারে — অর্থাৎ হাজারটা সংযোগ, আর ডেটাবেসটা ভেঙে পড়ে। DynamoDB-তে কোনো সংযোগ নেই, প্রতিটা কল একটা HTTPS অনুরোধ। পর্ব ১৬-এর ফাংশনটার জন্য এটাই আসল কারণ।
পর্ব ১৬-এ টেবিল বানানোর সময় একটা লাইন ছিল:
"KeySchema": [{"AttributeName": "event_id", "KeyType": "HASH"}]ওই HASH মানে partition key, আর এটাই DynamoDB-র একমাত্র সিদ্ধান্ত যেটা পরে বদলানো যায় না। Capacity বদলানো যায়, attribute যোগ করা যায়, index যোগ করা যায় — key বদলাতে হলে নতুন টেবিল বানিয়ে সব ডেটা সরাতে হয়।
কারণটা জানা দরকার, কারণ তাহলে সিদ্ধান্তটা ভালো নেওয়া যায়।
DynamoDB তোমার ডেটা অনেকগুলো physical partition-এ ছড়িয়ে রাখে — আলাদা মেশিন, আলাদা ডিস্ক। কোন আইটেম কোথায় যাবে, সেটা ঠিক হয় partition key-টার একটা hash থেকে। তাই:
• একটা আইটেম খুঁজতে hash হিসাব করে সোজা সেই partition-এ যাওয়া — তাই গতি ধ্রুব
• আর ডেটা কতটা সমানভাবে ছড়িয়েছে, সেটা পুরোপুরি key-র উপর নির্ভর করে
আর দ্বিতীয় বিন্দুটাই সমস্যার উৎস। একটা উদাহরণ দিয়ে দেখি।
খারাপ key: status
ধরা যাক একটা অর্ডারের টেবিল, আর partition key হলো status — যার মান pending, shipped বা delivered। তিনটে সম্ভাব্য মান, তাই তিনটে partition।
দশ লাখ অর্ডার তিনটে partition-এ। আর যেহেতু নতুন অর্ডার সব pending, সব লেখা একটা partition-এ যাচ্ছে। এটাকে বলে hot partition, আর লক্ষণটা হলো throttling — যখন টেবিলের মোট capacity যথেষ্ট থাকলেও লেখা আটকে যায়।
ভালো key: order_id
প্রতিটা আইটেমের আলাদা মান, তাই hash-গুলো সমানভাবে ছড়ায়, তাই লেখাগুলোও।
নিয়মটা তাই: partition key-তে অনেক আলাদা মান থাকতে হবে, আর ট্র্যাফিক সেগুলোর মধ্যে সমানভাবে ছড়াতে হবে।
তৃতীয় সারিটা একটা সূক্ষ্ম ফাঁদ: তারিখ দেখতে ভালো key মনে হয় (অনেক আলাদা মান), কিন্তু লেখাগুলো সবসময় আজকের তারিখে যাচ্ছে — অর্থাৎ এক সময়ে একটাই partition গরম।
আর দ্বিতীয় একটা key আছে — RANGE, বা sort key, আর এটাই DynamoDB-কে সত্যিই কাজের করে তোলে।
একটা টেবিলে দুটো key থাকলে — user_id (partition) আর created_at (sort) — তখন তুমি করতে পারো:
"এই ব্যবহারকারীর সব অর্ডার, নতুন থেকে পুরোনো, প্রথম ২০টা"
১৮৫টি অংশের ৩৭টি দেখানো হয়েছে, ১৪৮টি বাকি