কম্পিউটার টিউটোরিয়াল

রুবি অন রেইলস ডাটাবেস পারফরম্যান্স মাস্টার করুন: টেস্টিং ও অপ্টিমাইজেশন কৌশল

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

আপনি যখন একটি রেইলস অ্যাপ্লিকেশন ডেভেলপ করেন, ActiveRecord হল ডিফল্ট টুল যা আপনার ডাটাবেস ম্যানেজ করে। ActiveRecord একটি সহজ এবং দ্রুত ইন্টারফেস প্রদান করে ডেটা কোয়েরি এবং ইনসার্ট করার জন্য .where, .save, .create, এবং .update কমান্ডস ব্যবহার করে। রেইলস এই কমান্ডগুলো SQL কোয়েরিতে কনভার্ট করার কাজ করে, যা একটি ভালো জিনিস, কিন্তু কখনো কখনো পারফরম্যান্স ইস্যু সৃষ্টি করতে পারে। এটি গুরুত্বপূর্ণ যে আপনি কিছু সাধারণ ইস্যু এবং কীভাবে পারফরম্যান্স অপ্টিমাইজ করতে হয় সেটি বুঝেন।

রুবি অন রেইলসে ActiveRecord-র ওপর একটি দ্রুত নোট

রেইলস ActiveRecord Model-View-Controller (MVC)-এ একটি লেয়ার যা আপনার ডাটাবেস ম্যানেজ করে একটি বিজনেস অবজেক্ট হিসেবে রিপ্রেজেন্ট করে। ActiveRecord প্যাটার্ন ORM টেকনিক ব্যবহার করে একটি অ্যাপ্লিকেশনের অবজেক্টগুলোর রিলেশনাল ডাটাবেস টেবিল ম্যানেজমেন্ট সিস্টেমের সাথে কানেক্ট করতে।

এখন, চলুন শুরু করি!

রেইলসে ডাটাবেস পারফরম্যান্স ইস্যু চিহ্নিত ও টেস্ট করার ৩টি উপায়

১. ActiveRecord কোয়েরিতে Explain রান করুন

এক্সপ্লেইন (explain) স্টেটমেন্ট একটি SQL কোয়েরির এক্সিকিউশন প্ল্যান (execution plan) সম্পর্কে ইনফরমেশন ডিসপ্লে করে — কীভাবে একটি কোয়েরি এক্সিকিউট হবে, কত রো স্ক্যান হবে, কোন ইন্ডেক্স ব্যবহার হবে, এবং কীভাবে টেবিলগুলো জয়েন (join) হবে।

এক্সিকিউশন প্ল্যান আমাদের হেল্প করে কোয়েরি এক্সিকিউশন কী স্লো করছে সেটি বের করতে দেখে:

  • কোন ইন্ডেক্স আপনার যোগ করা উচিত কোয়েরির পারফরম্যান্স উন্নত করতে।
  • টেবিলগুলো অপ্টিমাল অর্ডারে জয়েন হয়েছে কিনা। আপনি STRAIGHT_JOIN ব্যবহার করতে পারেন জয়েন স্টেটমেন্টে টেবিল অর্ডার ফোর্স (force) করার জন্য बेटার পারফরম্যান্সের জন্য।

Explain SELECT, DELETE, INSERT, REPLACE এবং UPDATE স্টেটমেন্টসও ওপর কাজ করে।

ActiveRecord-এ explain ব্যবহার করা খুব সোজা। নিচের কমান্ড দিন:


কমান্ডের শেষে .explain যোগ করলে ActiveRecord কমান্ডসের জন্য কোয়েরি প্ল্যান मिलবে। উপরের উদাহরণটি একটি খুব সিম্পল কোয়েরি যা id (প্রাইমারি কি) ব্যবহার করে টেবিল কোয়েরি করে। explain স্টেটমেন্টের আউটপুট দেখাচ্ছে যে এটি pkey ব্যবহার করছে। এতে, আপনি নিশ্চিত হতে পারেন যে স্টেটমেন্টটি অপ্টিমাল এবং দ্রুত।

আপনি আপনার স্লো কোয়েরিগুলোর সাথে .explain কমান্ড যোগ করে দেখতে পারেন এক্সিকিউশন অর্ডার, সাথে ব্যবহার করা ইন্ডেক্স। যদি কোয়েরি প্ল্যান Seq Scan দেখায়, ইন্ডেক্স ব্যবহার হচ্ছে না এবং কোয়েরি চেঞ্জ বা একটি নতুন ইন্ডেক্স যোগ করা দরকার।

জয়েন (join) সহ আরেকটি উদাহরণ:


এখানে, ইউজার টেবিল collaborations টেবিলের সাথে জয়েন করা হয়েছে। কোয়েরি প্ল্যানে তাকালে, collaboration টেবিল seq scan ব্যবহার করছে এবং প্রথম এক্সিকিউট হচ্ছে — য 그때 ইউজার টেবিল pkey ইন্ডেক্স ব্যবহার করছে এবং পরে এক্সিকিউট হচ্ছে। আপনি collaborations টেবিলে user_id কলামে একটি ইন্ডেক্স যোগ করতে পারেন এই কোয়েরি অপ্টিমাইজ করতে। Explain কোয়েরি ব্রেক ডাউন করতে হেল্প করে, যাতে আপনি বের করতে পারেন কোথায় অপ্টিমাইজেশন দরকার।

২. কী ডাটাবেস মেট্রিক্স পরিমাপ করুন (Measure Key Database Metrics)

কোয়েরি টাইম একমাত্র মেট্রিক নয় যেটি পরিমাপ করলে বুঝতে পারবেন কোয়েরি পারফরম্যান্ট কিনা — আরও কিছু ডাটাবেস মেট্রিক্স দেখুন, যেন:

  1. CPU ইউজেজ
  2. মেমরি ইউজেজ
  3. ডিস্ক কিউ ফর ওয়েটিং IO (Disk queue for waiting IO)
  4. নেটওয়ার্ক ব্যান্ডউইডথ ফর ইনবাউন্ড এবং আউটবাউন্ড ট্রাফিক
  5. উপলব্ধ ডিস্ক স্পেস
  6. থ্রুপুট (Throughput)

কোয়েরি স্লো হয়ে যেতে পারে যখন এই মেট্রিক্স একটি নির্দিষ্ট থ্রেশহোল্ড (threshold) এর ওপর চলে যায়। আপনাকে একটি ডেটা পয়েন্ট একটি টাইম রেঞ্জ (time range) জুড়ে দেখতে হবে পারফরম্যান্স ইস্যু বুঝতে।

যে ডেটা পয়েন্টটি পরিমাপ করতে হবে সেটি অনেক ফ্যাক্টরের ওপর ডিপেন্ড করে, যেন:

  • ডাটাবেস টাইপ:

    • রিলেশনাল (Relational)
    • ইন-মেমরি (In-memory)
    • No-SQL
    • ডেটা-ওয়ারহাউস (Data-Warehouse)
  • সার্ভার কীভাবে হোস্টেড:

    • অন-প্রেমিসেস (On-premises)
    • ক্লাউডে (On the cloud)

ডাটাবেস মেট্রিক্স মনিটর করার কোনো সিঙ্গেল উপায় নেই — এটা বিভিন্ন ফ্যাক্টরের ওপর ডিপেন্ড করে।

৩. AppSignal ব্যবহার করে রেইলস অ্যাপ পারফরম্যান্স পরিমাপ করুন

সকল পারফরম্যান্স মেট্রিক্স ম্যানেজ করা কঠিন হতে পারে একটি সেন্ট্রাল প্লেস ছাড়া যা আপনাকে সকল কোয়েরির ওভার ভিজিবিলিটি (visibility) দেয়। প্রতিটি কোড ব্লকে পারফরম্যান্স কোড যোগ করা কামশুমার (cumbersome) এবং আনম্যানেজেবল (unmanageable)।

AppSignal-এর মতো টুলস সহ, আপনি সহজেই পারফরম্যান্স মেজারমেন্ট আপনার অ্যাপ্লিকেশনে ইন্টিগ্রেট করতে পারেন। AppSignal রেইলস আউট অফ দ্য বক্স সাপোর্ট করে। 'AppSignal for Ruby' ডকুমেন্টেশন থেকে সিম্পল AppSignal ইনস্টলেশন প্রসেস শিখুন।

নিচের ক্রিটিক্যাল মেট্রিক্সগুলোর ওপর চোখ রাখুন:

  • স্লো কোয়েরিজ (Slow queries)
  • থ্রুপুট ভিত্তিক ডাটাবেস পারফরম্যান্স
  • N+1 কোয়েরিজ (N+1 queries)
  • ডাটাবেস ল্যাটেন্সি (Database latency)
  • সক্রিয় কানেকশন সংখ্যা (Number of active connections)

এখানে একটি AppSignal ড্যাশবোর্ড কেমন দেখাতে পারে:

রুবি অন রেইলস ডাটাবেস পারফরম্যান্স মাস্টার করুন: টেস্টিং ও অপ্টিমাইজেশন কৌশল

রুবি অন রেইলস ডাটাবেস পারফরম্যান্স অপ্টিমাইজ করার ৭টি উপায়

১. N+1 কোয়েরির জন্য ইগার লোডিং (Eager Loading for N+1 Queries)

N+1 কোয়েরিজ সবচেয়ে সাধারণ ডাটাবেস পারফরম্যান্স সমস্যা। একটি N+1 কোয়েরি উদাহরণ দেখি যেখানে আপনার দুটি মডেল আছে — user এবং project:


এখন, আপনি যদি ইউজার এবং প্রজেক্ট নাম খুঁজতে চান, নিচের কোড চালান:


উপরের কোড প্রতিটি লুপে ডাটাবেস কোয়েরি করবে এবং পারফরম্যান্স ইস্যু সৃষ্টি করবে। এক্সিকিউট হওয়া টোটাল কোয়েরির সংখ্যা হবে ইউজার সংখ্যা + ১।

এই সমস্যা দূর করা খুব সহজ: অ্যাসোসিয়েশন ইগার লোড (eager load) করুন। কোয়েরির শেষে শুধু .includes(:projects) যোগ করুন:


এখন, লুপ এক্সিকিউট করলে ডাটাবেস কোয়েরি করবে না, কারণ উপরের কোয়েরি প্রজেক্টগুলো ইগার লোড করেছে:


রেইলস ৬.১ স্ট্রিক্ট লোডিং (strict loading) প্রদান করে নিশ্চিত করতে যে অ্যাসোসিয়েশন অ্যাক্সেস করার আগে ইগার লোডেড (eager loaded) হয়েছে। স্ট্রিক্ট লোডিং ইনাবেল করতে, মডেলে নিচের লাইন যোগ করুন:


এখন, আপনি যদি ইগার লোডিং ছাড়া প্রজেক্টস অ্যাক্সেস করার চেষ্টা করেন, রেইলস একটি ActiveRecord::StrictLoadingViolationError এক্সেপশন থ্রো করবে।

আপনার যদি রেইলস ৬.১ না থাকে, আপনি Bullet এর মতো জেমস ব্যবহার করতে পারেন।

২. ডাটাবেস ইন্ডেক্স ব্যবহার করুন (Use a Database Index)

ডাটাবেস ইন্ডেক্স (indexes) প্রদান করে ডেটা দ্রুত রিট্রিভ (retrieve) করতে। আগে কভার করা explain কমান্ড ব্যবহার করে, আপনি বের করতে পারবেন কোয়েরি একটি প্রপার ইন্ডেক্স ব্যবহার করছে কিনা।

আপনি একটি স্লো কোয়েরিকে একটি ইতিমধ্যে এক্সিস্টিং ইন্ডেক্স বা একটি অ্যাডেড ইন্ডেক্স ব্যবহার করতে পারেন যেটি পারফরম্যান্স উন্নত করতে সাহায্য করে।

MySQL-এ চার ধরনের ইন্ডেক্স আছে:

  1. প্রাইমারি কি (Primary key) - ইন্ডেক্স অটোমেটিক্যালি প্রাইমারি কিতে যোগ হয়, যা এটিকে ইউনিক (unique) নিশ্চিত করে
  2. ইউনিক (Unique) - ইউনিক কি ইন্ডেক্স নিশ্চিত করে যে একটি অ্যাট্রিবিউটে যোগ হওয়া আইটেমগুলো সবসময় ইউনিক
  3. ইন্ডেক্স (Index) - প্রাইমারি কি ছাড়া অন্যান্য অ্যাট্রিবিউটে যোগ করা হয়
  4. ফুল টেক্সট (Full text) - ক্যারেক্টার-বেসড ডেটা কোয়েরি করতে হেল্প করে

একটি ইন্ডেক্স B-Tree বা Hash ফরম্যাটে স্টোর করা হয়।

ইন্ডেক্স একটি সিঙ্গেল ফিল্ডে যোগ করা যায় বা মাল্টিপল ফিল্ডের কম্পোজিশন (composition) হিসেবে তৈরি করা যায়। একটি কম্পোজিট ইন্ডেক্স (composite index) কোয়েরি অপ্টিমাইজ করতে উপযোগী যেটি একাধিক ফিল্ড অন্তর্ভুক্ত করে। যখন শুধু একটি ইন্ডেক্স ব্যবহার করা হয়, এটিকে একটি বড় ডেটাসেট স্ক্যান (large dataset scan) দরকার পড়ে।

উদাহরণস্বরূপ, নিচের কোয়েরিতে দুটি ফিল্ড আছে:


"abc" প্রজেক্টে অনেক ইউজার থাকতে পারে এবং কান্ট্রি ফিল্ড স্ক্যান হবে। বড় রেজাল্ট ডেটাসেটের কারণে এটি একটি স্লো প্রসেস হতে পারে। এই কেসে, আপনি প্রজেক্ট এবং কান্ট্রি উভয় ফিল্ডে একটি কম্পোজিট ইন্ডেক্স যোগ করতে পারেন পারফরম্যান্স উন্নত করতে।

আপনি রেইলসে ইন্ডেক্স যোগ করতে পারেন নিচের ActiveRecord মাইগ্রেশন কমান্ডস ব্যবহার করে:

সিঙ্গেল ইন্ডেক্স:


কম্পোজিট ইন্ডেক্স:



৩. লিমিটস (Limits) ব্যবহার করুন

জত বেশি রেকর্ড ফেরত দেওয়া হয়, পারফরম্যান্স তত স্লো হয়। একাধিক কোয়েরি করা একটি বড় ডেটাসেট ফেরত দেয় এমন একটি সিঙ্গেল কোয়েরির চেয়ে ভালো।


পরবর্তী ১০০ ব্যাচ ফেচ (fetch) করতে, আপনি অফসেট (offset) ব্যবহার করতে পারেন:


এটি উল্লেখযোগ্যভাবে পারফরম্যান্স উন্নত করবে। এক জিনিস মনে রাখুন, উচ্চতর অফসেটের সাথে, একটি কোয়েরি স্লো হয়। অফসেটে একটি লিমিট যোগ করুন।

৪. বড় সংখ্যক আইটেম লোড করতে find_each ব্যবহার করুন

রেকর্ডস ওভার ইটারেট (iterate) করার সময়, রেইলসে সেগুলো ব্যাচ (batch) করুন बेटার পারফরম্যান্সের জন্য:


এটি একবার ডাটাবেসে সকল রেকর্ড কোয়েরি করবে এবং মেমরি ও ডাটাবেস পারফরম্যান্স ইস্যু সৃষ্টি করবে।

find_each বা find_in_batches ব্যবহার করলে একই অপারেশন ব্যাচে করার কারণে পারফরম্যান্স উন্নত হয়:


ডিফল্টলি, find_each ১,০০০ রেকর্ডের ব্যাচে কোয়েরি করে। আপনি ব্যাচ সাইজ পরিবর্তন করতে পারেন আর্গুমেন্ট হিসেবে ডিফাইন করে:


আপনি find_in_batchesও ব্যবহার করতে পারেন অপারেশনের প্রয়োজন অনুযায়ী। find_in_batches এবং find_each-এর পার্থক্য হল find_in_batches রেজাল্ট একটি মডেলের অ্যারে (array of models) হিসেবে ইয়িল্ড (yield) করে ইনডিভিজুয়াল রেকর্ডের বদলে।

৫. প্লাক (Pluck) ব্যবহার করে আপনার প্রয়োজনীয় ফিল্ড সিলেক্ট করুন

Plack কমান্ড একটি কোয়েরির রেজাল্টকে ডাইরেক্টলি একটি অ্যারে-এ কনভার্ট করে ActiveRecord অবজেক্টের বদলে।

যদি একটি কোয়েরি বড় রেজাল্ট ফেরত দেয়, Pluck ব্যবহার করলে কোড পারফরম্যান্স উন্নত হবে। Pluck শুধু ডাটাবেস থেকে একটি প্রয়োজনীয় ফিল্ড সিলেক্ট করে:


রেজাল্টটি মেন টেবিলের বদলে একটি ইন্ডেক্স থেকে ফেচ (fetch) হয় এবং সর্টস (sorts) ইনভল্ভড (involved) কোয়েরিগুলোর সাথে আরও ইফেক্টিভ।

৬. বাল্ক অপারেশনস (Bulk Operations) ব্যবহার করুন

বাল্ক ডিলিট (Bulk Delete) ActiveRecord অবজেক্ট ওভার লুপ করে একটি ডিলিট অপারেশন রেকর্ডগুলো এক এক করে ডিলিট করবে:


প্রতিটি রেকর্ড ডিলিট করতে অনেক কোয়েরি ডাটাবেসে করতে হয়। বদলে, একটি সিঙ্গেল বাল্ক delete_all কোয়েরি ব্যবহার করা অপ্টিমাল:


বাল্ক ক্রিয়েট (Bulk Create) কিছু লোক বুঝতে পারে না যে বাল্ক ডিলিটের মতই, আপনি ActiveRecord-এ বাল্ক ইনসার্ট (bulk insert) পারফর্ম করতে পারেন। এটি n সংখ্যক কোয়েরিকে শুধু একটি এ কমিয়ে দিতে পারে। ActiveRecord::Base create মেথড হ্যাশের একটি অ্যারে (array of hashes) ইনপুট হিসেবে নেয়:



৭. প্রয়োজন হলে ইন-মেমরি ক্যালকুলেশন (In-Memory Calculation) ব্যবহার করুন

কিছু ইনস্ট্যান্সে, কোয়েরি করার চেয়ে ইন-মেমরি ক্যালকুলেশন (in-memory calculation) ভালো। ধরি আমরা আমাদের ডাটাবেসে সেই কান্ট্রিগুলো খুঁজতে চাই যেগুলোর ইউজার রেকর্ড নেই:


উপরের কোয়েরি রেজাল্ট পেতে N কোয়েরি দরকার পড়ে। এর বদলে, আমরা একটি সিঙ্গেল কোয়েরি লিখতে পারি দেওয়া কান্ট্রিগুলোর ইউজার খুঁজতে এবং বাকি ক্যালকুলেশন মেমরিতে করতে:


আপনি ক্যাশ (cache) ব্যবহার করতে পারেন রিকোয়েস্ট-রেসপন্স সাইকেল রি-ইউজ (reuse) করতে এবং কিছু কেসে ডাটাবেস লোড কমাতে। রেইলস তিন ধরনের ক্যাশিং টেকনিক প্রদান করে: পেজ (page), অ্যাকশন (action), এবং ফ্র্যাগমেন্ট ক্যাশিং (fragment caching - ডিফল্টলি অফার করা হয়)।

সমাপন: ActiveRecord এবং AppSignal দিয়ে আপনার রুবি অন রেইলস পারফরম্যান্স অপ্টিমাইজ করুন

ঠিক আছে, রিক্যাপ (recap) করার সময়! এই পোস্টে, আমরা রেইলসে ডাটাবেস পারফরম্যান্স ইস্যু চিহ্নিত ও টেস্ট করার তিনটি উপায় কভার করেছি:

  • ActiveRecord কোয়েরিতে Explain রান করা
  • কী ডাটাবেস মেট্রিক্স পরিমাপ করা
  • AppSignal ব্যবহার করে রেইলস অ্যাপ পারফরম্যান্স পরিমাপ করা

এবং ডাটাবেস পারফরম্যান্স অপ্টিমাইজ করার সাতটি উপায়, যেন:

  • N+1 কোয়েরির জন্য ইগার লোডিং
  • একটি ডাটাবেস ইন্ডেক্স
  • লিমিটস
  • find_each বড় সংখ্যক আইটেম লোড করতে
  • Pluck ব্যবহার করে প্রয়োজনীয় ফিল্ড সিলেক্ট করা
  • বাল্ক অপারেশনস
  • ইন-মেমরি ক্যালকুলেশন

রেইলস অ্যাপ্লিকেশন ডেভেলপ করা সুপার ইজি (super easy) এবং ফাস্ট করে। ActiveRecord ডাটাবেস কোডের প্রোডাক্টিভিটি, রি-ইউজেবিলিটি (reusability), এবং মেইনটেইনেবিলিটি (maintainability) এ হেল্প করে। ActiveRecord কোয়েরিগুলো কীভাবে SQL কোয়েরিতে ট্রান্সলেট হয় এবং এক্সিকিউট হয় সেটি বুঝা গুরুত্বপূর্ণ।

তবে, আপনার রেইলস ডাটাবেস পারফরম্যান্স অপ্টিমাইজ করার জন্য সবচেয়ে গুরুত্বপূর্ণ জিনিস হল পারফরম্যান্স ডেটার ওভার ভিজিবিলিটি (visibility over performance data)। পারফরম্যান্স ইস্যুস সাধারণ, কিন্তু আপনি সেগুলো সমাধান করতে পারেন একবার আপনার কাছে এই ভিজিবিলিটি থাকলে। আপনাকে একটি প্রপার মনিটরিং টুল দরকার যা ডাটাবেস মেট্রিক্স দেয়। আমরা AppSignal পছন্দ করি ;)

P.S. আপনি যদি রুবি ম্যাজিক পোস্টগুলো প্রেস থেকে বের होतेই পড়তে চান, আমাদের রুবি ম্যাজিক নিউজলেটার সাবস্ক্রাইব করুন এবং একক পোস্টও মিস করবেন না!


  1. পাইথনে ম্যাটপ্লটলিব - ইমেজ ব্যাকগ্রাউন্ডের ওপর প্লট করা

  2. HTML5-এ ওয়েব ব্রাউজার সাপোর্ট চেক করা

  3. CSS3 ৩D ট্রান্সফর্ম ফাংশন (3D Transform Functions) ব্যবহার

  4. জাভাতে ডাইরেক্টরি থেকে শুধু ফাইল লিস্ট করা