Transaction in DBMS

What is a Transaction?

আজকের আড্ডায় আমরা জানতে যাচ্ছি ডাটাবেস Transaction নিয়ে। এটা কিন্তু সবচেয়ে গুরুত্বপূর্ণ বিষয়গুলোর একটা। এই কনসেপ্ট আপনি সব জায়গায় দেখতে পাবেন।

Transaction

আচ্ছা, তাহলে Transaction আসলে কি? এট মূলত দুইটা জিনিসঃ

  1. A Collection of Queries
  2. One unit of work

মানে হলো, এটা কিছু Queryর কালেকশন যাকে আমরা একটা ইউনিট হিশেবে ভাবতে পারি।

কেন আমরা এটাকে একটা ইউনিট হিশেবে দেখছি? কারন হলো , SQL বা Structured Query Language এর বৈশিষ্ট হলো, আমাদের ডাটাগুলো স্ট্রাকচারড থাকে। এর অনেক টেবিল থাকে। তাই সবকিছু একবারে করাটা কঠিন হয়ে যায়। একবারে বলতে এক Query তে বুঝাচ্ছি। কিছু ক্ষেত্রে এটা একদম অসম্ভব। তাই আপনি যা চাচ্ছেন, সেটা করতে আপনার এক বা একাধিক কুয়েরি লাগতে পারে। আপনি একটা Transaction শুরু করলেন এবং সেটা করতে আপনার তিনটা, চারটা, পাঁচটা , ছয়টা ইত্যাদি সংখ্যক কুয়েরি দরকার হতে পারে।

চলেন এবার একটা উদাহরণে যাই। ধরেন, আপনি Account deposit(SELECT, UPDATE, UPDATE) করতে চাচ্ছেন। মানে এক একাউন্ট থেকে আরেক একাউন্টে টাকা পাঠাবেন।

প্রথমে আপনাকে প্রথম একাউন্ট থেকে টাকা টা SELECT করে দেখতে হবে আসলেই সেখানে অত পরিমাণ টাকা আছে কিনা। তারপর সিলেক্ট করার পর আপনি সেই একাউন্টে একটা UPDATE করবেন, যাতে ১০০টাকা(ধরি) কেটে নেয়। তারপর আরেকটা একাউন্টে আবার UPDATEকরতে হবে। সেখানে আপনি টাকার পরিমাণ ১০০টাকা বাড়িয়ে দিবেন।

অর্থাৎ দেখা গেল, একটা Transaction করতে আপনি তিনটা ভিন্ন ভিন্ন কুয়েরি করলেন। A collection of queries to do one unit of work. আশা করি মাথা ক্লিয়ার হয়ে গেছে!

Transaction Lifespan

Transaction এর জীবনকাল।

Transaction BEGIN

একটা Transaction সবসময় শুরু হয়, BEGIN কী-ওয়ার্ড দিয়ে। এই কী-ওয়ার্ড ডাটাবেজকে বলে দেয় যে, এই শুনো, তুমি এখন একটা নতুন Transaction শুরু করতে যাচ্ছ, যার মধ্যে কয়েকটা Query থাকবে।

Transaction COMMIT

Transaction এ লেখা Query গুলো নিয়ে যখন আপনি সন্তুষ্ট, মানে কাজ টা ঠিকঠাক ভাবে হয়েছে, তখনও কিন্তু আসলে কাজ শেষ হয়নি। মানে কাজগুলো তখনও Durable না। আপনার ডিস্কে কাজগুলো স্থায়ীভাবে সেট হয়নি। ডাটাবেজে কাজগুলো Persist করবে যখন আপনি বলবেন, "এই ডাটাবেজ, আমি খুশি আমার কাজ নিয়ে, প্লিজ COMMIT করে দাও। এই Transaction এর Lifespan এ যা যা করেছি, সব COMMIT করে দাও। এই কমিট Transaction কে বলে দেয়, সব কিছু ডিস্কের মধ্যে যাতে Persistant ভাবে থাকে।

এখন চিন্তা করেন, এইযে কমিটের মধ্যে বিপুল পরিমাণ কাজ হচ্ছে ভিতরে ভিতরে, এটা আপনি কিভাবে করতেন? মানে আপনি যদি নিজেই ডাটাবেজ সিস্টেম তৈরী করতেন তাহলে কিভাবে করতেন?

ধরেন, আপনি ১০০০ কুয়েরি এক্সিকিউট করবেন, আপনি কি প্রতিবার প্রতিটা কুয়েরির সাথে সাথে ডিস্কে চেঞ্জগুলো ইমপ্লিমেন্ট করতেন, নাকি সবগুলো চেঞ্জ মেমরি তে রেখে অপেক্ষা করতেন, তারপর একবারে সবগুলো ডিস্কে ইমপ্লিমেন্ট করতেন?

সবকিছুরই ভালো মন্দ আছে। প্রথম উপায়ে কাজ করলে আপনার কমিটগুলো তুলনামূলক ফাস্ট হবে আর দ্বিতীয় পদ্ধতিতে আপনার কমিটগুলো তুলনামূলক স্লো হয়ে যাবে।

প্রত্যেকটারই কিছু সুবিধা অসুবিধা আছে। এবং আমরা এগুলো নিয়েই ভাবতে চাই এই আর্টিকেল সিরিজে। সত্যিকারে আসলে কি হচ্ছে ডাটাবেজের ভিতরে। একদম বেসিক জিনিসগুলো। একদম ফান্ডামেন্টালগুলো।

Transaction ROLLBACK

ধরেন, আপনি একটা ট্রান্সাকশনে ৫০,০০০ কুয়েরি করবেন(খুবই বাজে উদাহরণ আসলে!)। হঠাৎ আপনার মনে হল, উহু, আপনি করতে চাচ্ছেন না কাজটা, পুরোটা কাজটা আপনি Undo করতে চান। মানে ROLLBACK করতে চাচ্ছেন। কিভাবে করবেন?

উপরের ১০০০ কুয়েরির Transaction টার কথা ভাবেন। দুইটা উপায়ে করার কথা আলাপ করেছিলাম। প্রতিটা কুয়েরির সাথে সাথে কি আপনি সেটাকে ডিস্কে Persist করছিলেন? যদি করে থাকেন, তাহলে এখন আপনাকে প্রতিটা কাজ ডিস্ক থেকে Undo করতে হবে। যেটা আসলে বিপুল পরিমাণ কাজ!

আর দ্বিতীয় পদ্ধতিতে আপনি আপনি কিছুই ডিস্কে স্টোর করেন নি। আপনি সব করছিলেন মেমরি তে। তারপর সব শেষে ডিস্কে সেভ করার কথা ছিল। এই ডিস্কে রাইট করার আগে আপনি যা ইচ্ছা তাই করতে পারেন। ROLLBACK করা খুবই ফাস্ট হবে। কারণ আপনি ডিস্কে কিছুই লিখেন নি। শুধু মেমরি থেকে Flush করে দিলেই হবে।

Transaction unexpected ending = ROLLBACK(e.g. crash)

ধরেন, ডাটাবেজে কোন কাজ করছেন। ২০,০০০ কুয়েরির পর হঠাৎ ডাটাবেজ ক্র্যাশ করল! তখন কি হবে? যখন ডাটাবেস আবার ব্যাক করবে তখন যাতে সেটা ঠিকমতো আবার আগের জায়গায় ফেরত আসতে পারে। আপনি ডাটাবেস নিজে কোড করে বানানোর সময় আপনাকে এটাও মাথায় রাখতে হবে। বুঝতেই পারছেন, ডাটাবেস বানানো আসলে সহজ কাজ না।

আপনার নিজের ইউজকেস অনুযায়ী আপনি ডাটাবেস বানাবেন, এবং নিজের মত অপটিমাইজেশন করবেন। প্রতিটা ডাটাবেস নিজের মত করে এসব ফিচার এবং অপটিমাইজেশন করে থাকে। Postgres, SQL Server, MySQL সবাই নিজের মত করে এসব কাজ করে থাকে। ইঞ্জিনিয়াররা একেকজন একেক ধরণের অপটিমাইজেশন নিয়ে কাজ করে। কেউ হয়ত ক্র্যাশ গুলোর জন্য অপটিমাইজেশন করে। কেউ কমিটের ক্ষেত্রে অপটিমাইজেশন করে। এটা অবশ্য Postgres এর ক্ষেত্রে সত্য। Postgres এর কমিটগুলো খুবই ফাস্ট। Transaction এর সময় কোন যেকোন কুয়েরির সময় DB change টাকে Persist করার চেষ্টা করে। অর্থ্যাৎ Postgres প্রচুর পরিমাণ I/O অপারেশন করে, কিন্তু কমিটগুলো খুবই চমৎকার , খুবই ফাস্ট। অবশ্য এটা অন্য আলাপ।

এখানে একটা আলাপ মিস হয়ে গেছে। এমন যদি হয় , যে কমিট করার মুহুর্তে ডাটাবেস ক্র্যাশ করল? তখন কি হবে? ভয়ংকর ব্যাপার তাইনা? একেক ডাটাবেসে কমিট করার জন্য একেক রকম সময় লাগে। যদি এই সময় ক্র্যাশ করে তাহলে সর্বনাশ অবস্থা! যাহোক, প্রশ্ন রেখে গেলাম, পরের কোন আর্টিকেলে এটা নিয়ে আলাপ হবে।

Nature of Transactions

সাধারণত কোন ডাটা চেঞ্জ করার জন্য Transaction করা হয়। কিন্তু যদি চেঞ্জ করার উদ্দেশ্য না থাকে, শুধুমাত্র ডাটা Read করার জন্যও Transaction করা যেতে পারে। এতে অবাক হওয়ার কিছু নেই। এটা খুবই স্বাভাবিক।

যেমন ধরুন, আপনি একটা রিপোর্ট জেনারেট করতে চাচ্ছেন। এরকম সময় Transaction ছাড়াও কাজটা করতে পারবেন। আবার প্রতিটা কুয়েরিকেও একেকটা আলাদা Transaction বানাতে পারেন। কিন্তু এমন করা উচিত না। কেন? কারণ আপনি একটা Transaction এর মাধ্যমে Consistency মেইনটেইন করতে চান। এছাড়াও আপনি চান যেই নির্দিষ্ট সময়ে Transaction শুরু হয়েছে সেই সময়ের একটা Snapshot. এর মাঝে যদি অন্য আরও কিছু চেঞ্জ হয়ে যায়, আপনি তার পরোয়া করেন না। আপনি চান আপনার কাজটাকে Isolated রাখতে।

Transaction

অনেক কথা হলো উপরে। এবার চলেন একটু নিজেদের যাচাই করি। একটা কাজ দেই। কাজটা হলোঃ Send $100 From Account 1 to Account 2

| ACCOUNT_ID | BALANCE |

| :--------: | :-------: |

| 1 | $1000 |

| 2 | $500 |

এই কাজটা আপনি কিভাবে করবেন? এই একটা Transaction এ কি কি ধাপ থাকতে পারে বলে আপনার মনে হয়? আগে কিছু সময় দিয়ে নিজে নিজে ভাবুন।

Solution(not the best one):

  1. BEGIN TX1
    • SELECT BALANCE FROM ACCOUNT WHERE ACCOUNT_ID =1
    • BALANCE > 100
      • UPDATE ACCOUNT SET BALANCE=BALANCE - 100 WHERE ACCOUNT_ID=1
      • UPDATE ACCOUNT SET BALANCE=BALANCE+100 WHERE ACCOUNT_ID=2
  2. COMMIT TX1

প্রথমে আমরা BEGIN দিয়ে Transaction1 কে শুরু করলাম। তারপর সব আগে চেক করলাম, ACCOUNT_ID যার 1 , তার কত টাকা আছে। তারপর একটা Constraint দিলাম যে, টাকা কি ১০০ এর থেকে বেশি আছে? নাকি কম? ১০০ এর বেশি যখন আছে, তখন প্রথমে আমরা ACCOUNT_ID =1 থেকে ১০০ টাকা কেটে নিলাম। তারপর দ্বিতীয় একাউন্টে ১০০ টাকা বাড়িয়ে দিলাম। সবশেষে আমরা, COMMIT করে দিলাম, যাতে এই কুয়েরি গুলো শুধু মেমরিতে সীমাবদ্ধ না থাকে, যাতে এগুলো ডিস্কেও পার্মানেন্টলি লেখা হয়ে যায়। ব্যাস! কাজ শেষ।

শেষ কথা হলো, A transaction is a collection of queries that are treated as a single unit of work. এর মাধ্যমে ডাটা চেঞ্জ করা হতে পারে আবার শুধু মাত্র Read-only ও হতে পারে। এবং Transaction সবসমই শুরু হয়। হবেই। আপনি নিজে শুরু করতে পারেন, অথবা DBMS implicitly ভিতরে ভিতরে শুরু করে দেয়।

পরের আর্টিকেলগুলোতে দেখা হবে। আশা করি, বোরিং লাগেনি। লাগলে জানাবেন। I am always open to suggestions and criticism.