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

MongoDB-এ অনব্যবহৃত ইনডেক্স শনাক্ত করা: সর্বোত্তম পারফরম্যান্সের জন্য

ভার্সন ৩.২ থেকে, MongoDB প্রতিটি ইনডেক্সের ব্যবহারের পরিসংখ্যান ট্র্যাক করে। এই পরিসংখ্যানগুলি অ্যাক্সেস করতে, MongoDB $indexStats অ্যাগ্রিগেশন পাইপলাইন স্টেজ অফার করে। এখানে MongoDB-এ অনব্যবহৃত ইনডেক্স খুঁজে বের করার সময় বিবেচনা করার ছয় বিষয় দেওয়া হল।

উদাহরণস্বরূপ, নিম্নলিখিত কমান্ড "test.foo" সংগ্রহের ইনডেক্স পরিসংখ্যান প্রদান করবে:

db.foo.aggregate( [ { $indexStats: { } } ] )

https://bit.ly/2seXnzo

আমরা $indexStats আউটপুট বর্ণনা করব না কারণ এর ওপর প্রচুর ডকুমেন্টেশন এবং অনেক ভালো আর্টিকেল রয়েছে। পরিবর্তে, আমরা $indexStats অপারেটর ব্যবহার করার সময় বিভিন্ন এলাকায় ছয়টি বিবেচনা প্রদান করব।

বিবেচনা ১: পরিসংখ্যান প্রতিটি সার্ভিস রিস্টার্টে রিসেট হয়

$indexStats অপারেটর ব্যবহার করার সময় "accesses.since" ফিল্ডে অতিরিক্ত মনোযোগ দিন। কিছু কোয়ারী প্যাটার্ন কম번 бы্য হয়, যেমন দিনের শেষে ব্যাচ প্রসেস বা সাপ্তাহিক রিপোর্ট, তাই নিশ্চিত করুন যে আপনি যেটি মূল্যায়ন করবেন তার পরিসংখ্যানের সময়কাল আপনার প্রয়োজনীয়তা কভার করে। নিচের স্ক্রিপ্ট আপনাকে একটি থ্রেশহোল্ড (ঘণ্টায়) সেট করতে দেয় এবং যদি একটি অনব্যবহৃত ইনডেক্স মানদণ্ড পূরণ না করে তবে সতর্কতা প্রিন্ট করবে।

threshold_hours=24; db.foo.aggregate( [ { $indexStats: { } } ] ).forEach(function(f){if (f.accesses.ops==0) {if (ISODate()-f.accesses.since < threshold_hours*3600*1000) {print('Index: ' +f.name+ ' accessed: ' +f.accesses.ops+ ' times, Status:WARNING, The duration of statistics DOES NOT meet your compliance')} else {print('Index: ' +f.name+ ' accessed: ' +f.accesses.ops+ ' times, Status:OK The duration of statistics meet your compliance');};}})

আপনার জন্য সঠিক থ্রেশহোল্ড কী? এর কোন সহজ উত্তর নেই। সব স্টেটমেন্ট প্যাটার্ন একই ফ্রিকোয়েন্সিতে এক্সিকিউট হয় না, তাই সঠিক থ্রেশহোল্ড অ্যাপ্লিকেশন থেকে অ্যাপ্লিকেশনে ভিন্ন হয় এবং একই ডেটাবেসের মধ্যে সংগ্রহ প্রতি ভিন্নও হতে পারে।

বিবেচনা ২: সেকেন্ডারি রিডস

ডিফল্টভাবে, $indexStats প্রাইমারি থেকে পড়ে। যদি আপনার অ্যাপ্লিকেশন শুধু সেকেন্ডারি থেকে পড়ে, তবে $indexStats প্রাইমারিতে চালালে ভুল নিষ্কর্ষে পৌঁছাবে। সেকেন্ডারি থেকে ফলাফল পেতে, আপনি প্রথম বিবেচনার স্ক্রিপ্টটি ব্যবহার করতে পারেন, কিন্তু এর আগে db.getMongo().setReadPref('secondary') এক্সিকিউট করুন, যা কমান্ডটিকে সেকেন্ডারি থেকে পড়তে বাধ্য করে।

প্রশ্ন এখন: "যদি একটি সংগ্রহ প্রাইমারি এবং সেকেন্ডারি উভয়ই থেকে রিড পায়?" নিচের স্ক্রিপ্ট ব্যবহার করে, আপনি idx অ্যারে পপুলেট করতে পারেন সেই ইনডেক্সերով যা প্রাইমারি এবং সেকেন্ডারি উভয়ই-এ অনব্যবহৃত:

idx=[]; db.foo.getIndexes().forEach(function(f){idx.push(f.name)}) db.getMongo().setReadPref('primary'); db.foo.aggregate( [ { $indexStats: { } } ] ).forEach(function(f){if (f.accesses.ops>0) { var index = idx.indexOf(f.name); if (index > -1) {idx.splice(index, 1);};}}) db.getMongo().setReadPref('secondary'); db.foo.aggregate( [ { $indexStats: { } } ] ).forEach(function(f){if (f.accesses.ops>0) { var index = idx.indexOf(f.name); if (index > -1) {idx.splice(index, 1);};}})

idx অ্যারের কন্টেন্ট হবে প্রাইমারি এবং সেকেন্ডারি উভয়ই-এ অনব্যবহৃত ইনডেক্স। কমপ্লায়েন্স উইন্ডো (threshold_hours) সম্পর্কে কী? বিবেচনা ১-এর স্ক্রিপ্ট কিছুটা মডিফাই করে আমরা টাইম কমপ্লায়েন্স প্রয়োগ করতে পারি। কেবল অ্যাগ্রিগেশন অংশটিকে নিচেরটি দিয়ে রিপ্লেস করুন এবং setReadPref ব্যবহার করে প্রাইমারি এবং সেকেন্ডারির বিপরীতে স্ক্রিপ্টটি এক্সিকিউট করুন:

db.foo.aggregate( [ { $indexStats: { } } ,{$match:{"name" : {$in:idx}}}] ).

যদি প্রাইমারি এবং সেকেন্ডারি ভিন্ন কমপ্লায়েন্স ফলাফল ফেরত দেয়, তবে সেরা পদ্ধতি হল দুটি টিয়ার কমপ্লায়েন্ট হওয়া পর্যন্ত অপেক্ষা করা।

সেকেন্ডারি রিড প্রিফারেন্স ব্যবহার করলে "ভুল ফলাফল" আসতে পারে যদি একটি সেকেন্ডারি সম্প্রতি রিস্টার্ট হয়েছে এবং স্ক্রিপ্ট সেই সেকেন্ডারি বেছে নেয় পরিসংখ্যান টানার জন্য। এই কেসে, একটি ভাল পদ্ধতি হল db.serverStatus().uptime চেক করা এবং বেশি আপটাইম वाले সেকেন্ডারি বেছে নেওয়া। আপটাইম মেথডের জন্য স্ক্রিপ্টে ভিন্ন পদ্ধতি দরকার যা এই ব্লগ পোস্টের ভবিষ্যত রিভিশনে ইমপ্লিমেন্ট করা হবে।

বিবেচনা ৩: রেপ্লিকা সেট ট্যাগস

রেপ্লিকা সেট ট্যাগস অনেক ইউজ কেসে প্রযোজ্য কিন্তু मुख্যভাবে জিও-রেপ্লিকেশন সিনেরিওতে রিড লোকালিটির জন্য এবং নির্দিষ্ট ওয়ার্কলোড নিবেদিত নোডগুলিতে টার্গেট করার জন্য ব্যবহার হয় (যেমন, ভারী অ্যানালিটিক্স অপারেশন)। ওয়ার্কলোড টার্গেটিং când, ট্যাগ করা নোডগুলো আলাদা আলাদা পরীক্ষা করতে হবে কারণ তারা এমন ইনডেক্স বা ইনডেক্সগুলো ব্যবহার করতে পারে যা অন্যান্য নোড ব্যবহার করে না। জিও-রেপ্লিকেশনে এটিরও কম দেখা যায়। বিবেচনা ১-এর স্ক্রিপ্টটি ব্যবহার করে একটি ট্যাগ করা মেম্বার চেক করা যায়, শুরুতে readPreference যোগ করে। এনালিটিক্সের জন্য মার্ক করা একটি সেকেন্ডারিতে রিড প্রিফারেন্স সেট করার উদাহরণ:

 db.getMongo().setReadPref('secondary', [ { "workload": "analytics" } ] ) . 

বিবেচনা ২-এর শেষ প্যারাগ্রাফে বর্ণিত ভবিষ্যতের পদ্ধতিটি ট্যাগ করা সেকেন্ডারিগুলো চেক করার জন্যও প্রসারিত করা যেতে পারে।

বিবেচনা ৪: TTL ইনডেক্স

TTL ইনডেক্স অপারেশন সার্ভ করে কিন্তু এর প্রধান ব্যবহার ডেটা প্রুনিং-র জন্য। $indexStats এই ইনডেক্সগুলোকে অনব্যবহৃত রিপোর্ট করার সম্ভাবনা বেশি কারণ TTL মনিটর ইনডেক্স অপারেশন হিসেবে গণনা হয় না। আপনি অবশ্যই $indexStats রিপোর্টের ফাইন্ডিংসের ভিত্তিতে TTL ইনডেক্স ড্রপ করতে চান না, তাই স্ক্রিপ্টগুলাকে এই টাইপের ইনডেক্স বাদ দিতে হবে।

দ্বিতীয় সেকশন থেকে idx অ্যারে পপুলেট করার স্ক্রিপ্টে একটু মডিফিকেশন করলে কাজ হয়ে যাবে। দ্বিতীয় লাইনটি নিচেরটির সাথে রিপ্লেস করলে idx অ্যারেতে কোনো TTL ইনডেক্স থাকবে না।

db.foo.getIndexes().forEach(function(f){if (f.expireAfterSeconds==undefined) {idx.push(f.name)}})

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

বিবেচনা ৫: শার্ডেড ক্লাস্টার

শার্ডেড ক্লাস্টারের কথা বললে, $indexStats আউটপুট মূল্যায়ন করার আগে দুটি বিষয় বিবেচনা করতে হবে। প্রথম, শার্ডেড সংগ্রহের বিরুদ্ধে $indexStats ব্যবহার করলে, শার্ড কী ইনডেক্স অনব্যবহৃত হিসেবে ক্লাসিফাই হয়ে যেতে পারে। উদাহরণস্বরূপ, একটি রাইট-হеви সংগ্রহ যা {_id:”hashed”} দিয়ে শার্ড করা হয়েছে (লিখার সমান বিতরণের জন্য) কিন্তু _id ইনডেক্স ব্যবহার করার কোনো রিড/আপডেট/ডিলিট অপারেশন নেই। এই কেসে, {_id:”hashed”} অনব্যবহৃত রিপোর্ট করে। ইনডেক্স ড্রপ করা ভাল আইডিয়া নয় কারণ এটা আপনার শার্ডেড ক্লাস্টার ভাঙিয়ে দেবে। যদি আপনি 'stats.foo' সংগ্রহের জন্য শার্ড কী এক্সক্লুড করতে চান, তবে নিচের স্ক্রিপ্ট বিবেচনা দুটি (সেকেন্ডারি রিডস) তে সংযুক্ত করা যেতে পারে এবং শার্ড কী idx অ্যারে থেকে বাদ পাবে।

shardkey=db.getSiblingDB('config').collections.findOne({_id:'stats.foo'},{_id:0,key:1}); db.foo.getIndexes().forEach(function(f){if (JSON.stringify(f.key)!=JSON.stringify(shardkey.key)) {printjson(shardkey.key);printjson(f.key);idx.push(f.name)}})

দ্বিতীয় বিবেচনা $indexStats আউটপুট সম্পর্কে, কারণ এখন এটি প্রতিটি শার্ড থেকে পরিসংখ্যান ফেরত দেয় যেখানে সংগ্রহটির উপস্থিতি রয়েছে। যদিও এটি অসাধারণ, কিন্তু এমন কেস থাকে যেখানে একটি ইনডেক্স কিছু শার্ডে অনব্যবহৃত রিপোর্ট করে যখন অন্যান্য শার্ড তা ব্যবহার করে। একটি খারাপ শার্ড কী কারণ হতে পারে কিন্তু সবচেয়ে সাধারণ সিনেরিও "কভারিং ইনডেক্স" নামে পরিচিত।

কভারিং ইনডেক্স ভালো বোঝার জন্য একটি উদাহরণ: ইনডেক্স {a:1} এবং {a:1,b:1} উভয়ই ফিল্ড 'a'-তে ইক্যুয়ালিটি ম্যাচ সার্ভ করতে পারে। যদি শার্ডএ'র অপ্টিমাইজার {a:1} বেছে নেয় এবং শার্ডবি'র {a:1,b:1} বেছে নেয়, তবে দুটি ইনডেক্সই কমপক্ষে একটি শার্ডের জন্য অনব্যবহৃত রিপোর্ট করবে।

চ্যালেঞ্জ হল গ্লোবালি কোন ইনডেক্সগুলো ব্যবহার হচ্ছে না সেটা খুঁজে বের করা। বিবেচনা ২-এর স্ক্রিপ্ট (সেকেন্ডারি রিডস) এর অ্যাগ্রিগেশন অংশ (forEach লুপ দ্বারা অনুসৃত) নিচেরটির সাথে রিপ্লেস করলে কাজ হয়ে যাবে:

db.foo.aggregate( [ { $indexStats: { } } , {$group: {_id:"$name",number : {$sum:"$accesses.ops"}}}] ).forEach(function(f){if (f.number>0) { var index = idx.indexOf(f._id); if (index > -1) {idx.splice(index, 1);};}})

আরেকটি চ্যালেঞ্জ আংশিকভাবে ব্যবহৃত ইনডেক্সগুলো খুঁজে বের করা। এই তথ্যটি রিডান্ডান্ট ইনডেক্স বা ইনডেক্স আইডেনটিফিকেশন ম্যালফাংশন случаয় সহায়ক হতে পারে। idx অ্যারে ব্যবহার করে, নিচের অ্যাগ্রিগেশন/স্ক্রিপ্ট গ্লোবালি অনব্যবহৃত ইনডেক্স দিয়ে পপুলেট করা হয় এবং আংশিক-রূপে-ব্যবহৃত ইনডেক্স রিপোর্ট করে:

db.foo.aggregate( [ { $indexStats: { } },{$match:{name:{$nin:idx},"accesses.ops":0}}]).forEach(function(f){print("Index "+f.name+" reports as partially unused on shard/host " +f.host)})

বিবেচনা ৬: লিস্ট-ইউজড ইনডেক্স

অনব্যবহৃত ইনডেক্স শনাক্ত করা এবং ড্রপ করা অত্যন্ত গুরুত্বপূর্ণ কিন্তু কম-ব্যবহৃত ইনডেক্স 評価 করা ও গুরুত্বপূর্ণ। যদি একটি ইনডেক্স সপ্তাহে বা মাসে এক বা দুবার অ্যাক্সেস হয়, তবে এটা বোঝাতে পারে যে আপনার ওয়ার্কলোডের জন্য এটি প্রয়োজনীয় বা লাভজনক নয়। পর্যায়ক্রমে কম-ব্যবহৃত ইনডেক্স চেক করা একটি ভাল অভ্যাস নিচের অ্যাগ্রিগেশন ব্যবহার করে:

db.foo.aggregate( [ { $indexStats: { } },{$match:{"accesses.ops":{$gt:0}}},{$group: {_id:"$name",number : {$sum:"$accesses.ops"}}},{$sort:{number:1}}] )

তারপর উপযুক্ত কর্ম কাটুন যা হতে পারে ইনডেক্স ড্রপ করা, ইনডেক্স ডেফিনিশন পরিবর্তন করা, বা এমনকি আপনার স্কিমা/অ্যাপ্লিকেশন লজিক পরিবর্তন করা ইনডেক্সগুলো রিডান্ডান্ট করার জন্য।

আমরা আপনার পাশে আছি

আমরা আপনার MongoDB ইনস্ট্যান্সের ইনডেক্স পরিষ্কার করতে সাহায্য করতে এখানে আছি। আপনাকে কেবল support@objectrocket.com-এ একটি টিকেট তৈরি করতে হবে এবং আমরা আপনার ইনডেক্স উন্নত করতে সাহায্য করব!

  1. MongoDB সিকিউরিটি সেরা অনুশীলন: আপনার ডেটা এখনই সুরক্ষিত করুন

  2. Docker কন্টেইনারে MongoDB ডিপ্লয়: ধাপে ধাপে গাইড

  3. MongoDB Compass আবিষ্কার করুন: সিমলেস ডেটা ম্যানেজমেন্টের জন্য আপনার ভিজ্যুয়াল টুল

  4. মঙ্গোডিবিতে কোড ইনজেকশন আটাক রোধ: একটি ডেভেলপার গাইড