এক অনন্য সূচকের অন্বেষণের জন্য (একই) 1000 এর আনুমানিক ব্যয় কেন এই পরিকল্পনাগুলিতে পৃথক?


27

উভয় কার্যনির্বাহী পরিকল্পনার নীচে প্রশ্নের মধ্যে একটি অনন্য সূচকে 1000 সন্ধানের অনুমান করা হয়।

সিক্স একই উত্স টেবিলের উপর অর্ডারযুক্ত স্ক্যান দ্বারা চালিত হয় যাতে আপাতদৃষ্টিতে একই ক্রমে একই মানগুলি সন্ধান করা উচিত।

উভয় নেস্ট লুপ আছে <NestedLoops Optimized="false" WithOrderedPrefetch="true">

যে কেউ প্রথম পরিকল্পনায় এই কাজটি 0.172434 এ তবে দ্বিতীয়টিতে 3.01702 এ কেন অর্জিত হয় তা যে কেউ জানেন?

(প্রশ্নের কারণ হ'ল প্রথম ক্যোয়ারী আপাতত কম পরিকল্পনা ব্যয়ের কারণে আমাকে অপ্টিমাইজেশন হিসাবে প্রস্তাব করেছিল। এটি আসলে আমার কাছে দেখে মনে হচ্ছে এটি আরও বেশি কাজ করে তবে আমি কেবল তাত্পর্যটি ব্যাখ্যা করার চেষ্টা করছি ... ।)

সেটআপ

CREATE TABLE dbo.Target(KeyCol int PRIMARY KEY, OtherCol char(32) NOT NULL);

CREATE TABLE dbo.Staging(KeyCol int PRIMARY KEY, OtherCol char(32) NOT NULL); 

INSERT INTO dbo.Target
SELECT TOP (1000000) ROW_NUMBER() OVER (ORDER BY @@SPID), LEFT(NEWID(),32)
FROM master..spt_values v1,  
     master..spt_values v2;

INSERT INTO dbo.Staging
SELECT TOP (1000) ROW_NUMBER() OVER (ORDER BY @@SPID), LEFT(NEWID(),32)
FROM master..spt_values v1;

প্রশ্ন 1 "পরিকল্পনাটি আটকান" লিঙ্ক link

WITH T
     AS (SELECT *
         FROM   Target AS T
         WHERE  T.KeyCol IN (SELECT S.KeyCol
                             FROM   Staging AS S))
MERGE T
USING Staging S
ON ( T.KeyCol = S.KeyCol )
WHEN NOT MATCHED THEN
  INSERT ( KeyCol, OtherCol )
  VALUES(S.KeyCol, S.OtherCol )
WHEN MATCHED AND T.OtherCol > S.OtherCol THEN
  UPDATE SET T.OtherCol = S.OtherCol;

প্রশ্ন 2 "পরিকল্পনাটি আটকান" লিঙ্ক

MERGE Target T
USING Staging S
ON ( T.KeyCol = S.KeyCol )
WHEN NOT MATCHED THEN
  INSERT ( KeyCol, OtherCol )
  VALUES( S.KeyCol, S.OtherCol )
WHEN MATCHED AND T.OtherCol > S.OtherCol THEN
  UPDATE SET T.OtherCol = S.OtherCol; 

প্রশ্ন ঘ

প্রশ্ন 2

উপরেরটি এসকিউএল সার্ভার 2014 (এসপি 2) (KB3171021) - 12.0.5000.0 (এক্স 64) এ পরীক্ষা করা হয়েছিল


@ জো ওবিশ মন্তব্যগুলিতে উল্লেখ করেছেন যে সরল তিরস্কার হবে

SELECT *
FROM staging AS S 
  LEFT OUTER JOIN Target AS T 
    ON T.KeyCol = S.KeyCol;

বনাম

SELECT *
FROM staging AS S 
  LEFT OUTER JOIN (SELECT * FROM Target) AS T 
    ON T.KeyCol = S.KeyCol;

উভয় 1,000 সারি উপস্থাপনকারী টেবিলের জন্য উপরে এখনও উদ্ভূত টেবিল ছাড়া নেস্টেড loops সঙ্গে একই পরিকল্পনা আকৃতি এবং পরিকল্পনা আছে প্রকাশমান সস্তা, কিন্তু একটি 10,000 সারি উপস্থাপনকারী টেবিল এবং খরচ মধ্যে পার্থক্য উপরে হিসাবে একই লক্ষ্য টেবিল পরিকল্পনা পরিবর্তন করে আকৃতির (সম্পূর্ণ স্ক্যান এবং মার্জ ব্যয় করে ব্যয়বহুল কাস্টেড সিক্সের তুলনায় তুলনামূলক বেশি আকর্ষণীয় বলে মনে হচ্ছে) ব্যয়টির এই তাত্পর্য দেখানো কেবল পরিকল্পনাগুলির সাথে তুলনা করা আরও শক্ত করে তোলা ব্যতীত অন্য প্রভাব ফেলতে পারে।

এখানে চিত্র বর্ণনা লিখুন

উত্তর:


20

যে কেউ প্রথম পরিকল্পনায় এই কাজটি 0.172434 এ তবে দ্বিতীয়টিতে 3.01702 এ কেন অর্জিত হয় তা যে কেউ জানেন?

সাধারণভাবে বলতে গেলে, নেস্টেড লুপস জোনের নীচের অভ্যন্তরীণ দিকটি এলোমেলো I / O প্যাটার্ন ধরে ধরে আটকানো হয়। পরবর্তী অ্যাক্সেসগুলির জন্য একটি সহজ প্রতিস্থাপন-ভিত্তিক হ্রাস রয়েছে, পূর্ববর্তী পুনরাবৃত্তির দ্বারা প্রয়োজনীয় পৃষ্ঠাটি ইতিমধ্যে মেমরিতে আনা হয়েছে এমন সুযোগের জন্য অ্যাকাউন্টিং। এই প্রাথমিক মূল্যায়ন স্ট্যান্ডার্ড (উচ্চ) ব্যয় উত্পাদন করে।

এখানে আরও একটি দামের ইনপুট রয়েছে, স্মার্ট সিক কস্টিং , যা সম্পর্কে খুব কম বিশদ জানা যায়। আমার অনুমান (এবং এটি এই পর্যায়ে রয়েছে) হ'ল এসএসসি অভ্যন্তরীণ দিকটি আরও বিশদভাবে I / O ব্যয়ের মূল্যায়ন করার চেষ্টা করে, সম্ভবত স্থানীয় ক্রম এবং / অথবা মানগুলি আনার জন্য বিবেচনা করে। কে জানে.

উদাহরণস্বরূপ, প্রথম সন্ধানকারী অপারেশনটি কেবল অনুরোধ করা সারিটিই নয়, সেই পৃষ্ঠায় সমস্ত সারি (সূচী ক্রমে) নিয়ে আসে। সামগ্রিক অ্যাক্সেস প্যাটার্ন দেওয়া, 1000 সন্ধানে 1000 সারি আনার জন্য কেবল পঠিত-অগ্রিম এবং প্রিফেচিং অক্ষম থাকা সত্ত্বেও 2 টি শারীরিক পাঠ প্রয়োজন। সেই দৃষ্টিকোণ থেকে, ডিফল্ট I / O ব্যয় একটি উল্লেখযোগ্য ওভারসেসিমেট প্রতিনিধিত্ব করে এবং এসএসসি-সমন্বিত ব্যয় বাস্তবতার কাছাকাছি।

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

দুর্ভাগ্যজনক যে subquery বাইরের অনুমানের জন্য কম্পিউট স্কেলারটি এখানে এসএসসিতে হস্তক্ষেপ বলে মনে হচ্ছে। গণনা স্কেলারগুলি সাধারণত যোগদানের উপরে স্থানান্তরিত হয় তবে এইগুলি যেখানে থাকে সেখানেই থাকতে হয়। তবুও, বেশিরভাগ সাধারণ কম্পিউট স্কেলারগুলি অপ্টিমাইজেশনের ক্ষেত্রে বেশ স্বচ্ছ, সুতরাং এটি কিছুটা অবাক করার মতো।

নির্বিশেষে, যখন PhyOp_Rangeকোনও সূচকে সাধারণ নির্বাচন থেকে শারীরিক ক্রিয়াকলাপ তৈরি করা হয় তখন SelIdxToRngএসএসসি কার্যকর হয়। যখন আরও জটিল SelToIdxStrategy(একটি সূচী কৌশলতে কোনও টেবিলে নির্বাচন করা) নিযুক্ত করা হয়, PhyOp_Rangeফলাফল এসএসসি চালায় তবে ফলাফল হ্রাস পায় না। আবার, এটি মনে হয় যে সহজ, আরও প্রত্যক্ষ কাজগুলি এসএসসির সাথে সবচেয়ে ভাল কাজ করে।

আমি আশা করি যে এসএসসি ঠিক কী করে তা আপনাকে বলতে পারতাম এবং সঠিক গণনাগুলি প্রদর্শন করতে পারতাম তবে আমি সেগুলি বিশদ জানি না। আপনি যদি নিজের জন্য উপলব্ধ সীমিত ট্রেস আউটপুটটি অন্বেষণ করতে চান তবে আপনি অননুমোদিত ট্রেস পতাকা 2398 ব্যবহার করতে পারেন An উদাহরণ আউটপুটটি হ'ল:

স্মার্ট সিক কস্টিং (7.1) :: 1.34078e + 154, 0.001

এই উদাহরণটি মেমো গ্রুপ 7, বিকল্প 1, ব্যয়ের উপরের সীমাবদ্ধতা এবং 0.001 এর একটি ফ্যাক্টর সম্পর্কিত। পরিষ্কার পরিচ্ছন্ন বিষয়গুলি দেখতে, পৃষ্ঠাগুলি যথাসম্ভব ঘন হওয়ার কারণে সমান্তরালতা ছাড়াই টেবিলগুলি পুনরায় তৈরি করতে ভুলবেন না। এটি না করে ফ্যাক্টরটি আপনার উদাহরণ টার্গেট টেবিলের জন্য আরও 0.000821 এর মতো। অবশ্যই সেখানে কিছুটা সুস্পষ্ট সম্পর্ক রয়েছে।

এসএসসিকে অননুমোদিত ট্রেস পতাকা 2399 দিয়ে অক্ষম করা যেতে পারে that পতাকাটি সক্রিয় হওয়ার সাথে সাথে উভয় ব্যয়ই উচ্চতর মান।


8

নিশ্চিত নয় যে এটি একটি উত্তর তবে মন্তব্যটির জন্য এটি কিছুটা দীর্ঘ। পার্থক্যের কারণটি আমার পক্ষে খাঁটি জল্পনা এবং সম্ভবত অন্যের চিন্তার জন্য খাদ্য হতে পারে।

কার্যকর করার পরিকল্পনার সাথে সহজতর ক্যোয়ারী।

SELECT S.KeyCol, 
       S.OtherCol,
       T.*
FROM staging AS S 
  LEFT OUTER JOIN Target AS T 
    ON T.KeyCol = S.KeyCol;

SELECT S.KeyCol, 
       S.OtherCol,
       T.*
FROM staging AS S 
  LEFT OUTER JOIN (
                  SELECT *
                  FROM Target
                  ) AS T 
    ON T.KeyCol = S.KeyCol;

এখানে চিত্র বর্ণনা লিখুন

এই সমতুল্য প্রশ্নের মধ্যে মূল পার্থক্য যা প্রকৃতপক্ষে অভিন্ন বাস্তবায়ন পরিকল্পনার ফলাফল হতে পারে তা হ'ল গণনা স্কেলার অপারেটর। কেন সেখানে থাকতে হবে তা আমি জানি না তবে আমি অনুমান করি যে এটি অপ্টিমাইজারটি উত্পন্ন টেবিলটি অপ্টিমাইজ করতে যেতে পারে is

আমার অনুমান যে কম্পিউট স্কেলারের উপস্থিতি হ'ল দ্বিতীয় ক্যোয়ারীর জন্য আইও খরচ ব্যয় করে।

অপ্টিমাইজারের ভিতরে থেকে : পরিকল্পনা ব্যয়

প্রথম সারির জন্য সিপিইউ ব্যয় 0.0001581 এবং পরবর্তী সারিতে 0.000011 হিসাবে গণনা করা হয়।
...
0.003125 এর আই / ও দাম হ'ল 1/320 - মডেলটির এই ধারণাটি প্রতিফলিত করে যে ডিস্ক সাবসিস্টেম প্রতি সেকেন্ডে 320 এলোমেলো I / O ক্রিয়াকলাপ সম্পাদন করতে পারে
... মূল্যবান
উপাদানটি মোট স্মার্ট হিসাবে স্বীকৃত যে পৃষ্ঠাগুলি ডিস্ক থেকে আনতে হবে সেগুলি পুরো টেবিলটি সংরক্ষণ করার জন্য প্রয়োজনীয় পৃষ্ঠাগুলির সংখ্যার বেশি হতে পারে না।

আমার ক্ষেত্রে সারণীটি 5618 পৃষ্ঠাগুলি নেয় এবং 1000000 সারি থেকে 1000 সারি পেতে প্রয়োজনীয় পৃষ্ঠাগুলির আনুমানিক সংখ্যা 5.618 হয় আইও ব্যয় 0.015625 দেয়।

উভয় কোয়েরি সিউমের সিপিইউ কস্ট একই হতে পারে 0.0001581 * 1000 executions = 0.1581,।

সুতরাং উপরের লিঙ্কযুক্ত নিবন্ধ অনুযায়ী আমরা প্রথম ক্যোয়ারীর জন্য 0.173725 হওয়া ব্যয় গণনা করতে পারি।

এবং ধরে নিচ্ছি যে আমি গণনা স্কেলারটি আইও কস্টের কোনও জগাখিচুড়ি তৈরি করছে সে সম্পর্কে এটি গণনা করা যায় 3.2831।

পরিকল্পনাগুলিতে যা দেখানো হয়েছে তা ঠিক তা নয় তবে এটি ঠিক আশেপাশে রয়েছে।


6

(পলের উত্তরের মন্তব্য হিসাবে এটি আরও ভাল হবে তবে আমার কাছে এখনও যথেষ্ট প্রতিনিধি নেই have)

আমি ট্রেস ফ্ল্যাগগুলির তালিকা সরবরাহ করতে চেয়েছিলাম (এবং কয়েকটি DBCCবিবৃতি) আমি নিকট-সিদ্ধান্তে পৌঁছাতাম, যদি ভবিষ্যতে অনুরূপ তাত্পর্যগুলি তদন্ত করতে সহায়তা করে। এই সমস্ত উত্পাদন ব্যবহার করা উচিত নয়

প্রথমত, আমি শারীরিক অপারেটরগুলি কীভাবে ব্যবহার করা হচ্ছে তা দেখার জন্য ফাইনাল মেমোটিতে আমার নজর ছিল। গ্রাফিকাল এক্সিকিউশন প্ল্যান অনুযায়ী তারা অবশ্যই একই দেখায়। সুতরাং, আমি ট্রেস পতাকা ব্যবহার করেছি 3604এবং 8615, প্রথমটি ক্লায়েন্টকে আউটপুট নির্দেশ করে এবং দ্বিতীয়টি ফাইনাল মেমো প্রকাশ করে:

SELECT S.*, T.KeyCol
FROM Staging AS S
      LEFT OUTER JOIN Target AS T
       ON T.KeyCol = S.KeyCol
OPTION(QUERYTRACEON 3604, -- Output client info
       QUERYTRACEON 8615, -- Shows Final Memo structure
       RECOMPILE);

থেকে ফিরে সন্ধান করে Root Group, আমি প্রায় এই একই রকম PhyOp_Rangeঅপারেটরগুলি পেয়েছি :

  1. PhyOp_Range 1 ASC 2.0 Cost(RowGoal 0,ReW 0,ReB 999,Dist 1000,Total 1000)= 0.175559(Distance = 2)
  2. PhyOp_Range 1 ASC 3.0 Cost(RowGoal 0,ReW 0,ReB 999,Dist 1000,Total 1000)= 3.01702(Distance = 2)

আমার কাছে কেবলমাত্র স্পষ্ট পার্থক্যটি ছিল 2.0এবং 3.0যা তাদের নিজ নিজ "মেমো গ্রুপ 2, মূল" এবং "মেমো গ্রুপ 3, আসল" উল্লেখ করে। মেমোটি পরীক্ষা করা হচ্ছে, এগুলি একই জিনিসটিকে বোঝায় - তাই কোনও পার্থক্য এখনও প্রকাশিত হয়নি।

দ্বিতীয়ত, আমি ট্রেস ফ্ল্যাগগুলির পুরো গণ্ডগোলের দিকে তাকিয়েছিলাম যা আমার কাছে ফলহীন প্রমাণিত হয়েছিল - তবে কিছু আকর্ষণীয় সামগ্রী রয়েছে। আমি বেনিয়ামিন নেভেরেজের কাছ থেকে সর্বাধিক তুলে নিয়েছি । আমি অপ্টিমাইজেশন বিধিগুলি সম্পর্কে একটি সূত্র খুঁজছিলাম যা একটি ক্ষেত্রে প্রয়োগ হয়েছিল এবং অন্যটি নয়।

 SELECT S.*, T.KeyCol
 FROM Staging AS S
      LEFT OUTER JOIN Target AS T
        ON T.KeyCol = S.KeyCol
 OPTION (QUERYTRACEON 3604, -- Output info to client
         QUERYTRACEON 2363, -- Show stats and cardinality info
         QUERYTRACEON 8675, -- Show optimization process info
         QUERYTRACEON 8606, -- Show logical query trees
         QUERYTRACEON 8607, -- Show physical query tree
         QUERYTRACEON 2372, -- Show memory utilization info for optimization stages 
         QUERYTRACEON 2373, -- Show memory utilization info for applying rules
         RECOMPILE );

তৃতীয়ত, আমি লক্ষ্য করেছি PhyOp_Rangeযে আমাদের বিধিগুলির জন্য কোন বিধি প্রয়োগ করা হয়েছিল যা দেখতে দেখতে একই রকম। আমি একটি ব্লগ পোস্টে পল দ্বারা উল্লিখিত দু'টি ট্রেস পতাকা ব্যবহার করেছি ।

SELECT S.*, T.KeyCol
FROM Staging AS S
      LEFT OUTER JOIN (SELECT KeyCol
                      FROM Target) AS T
       ON T.KeyCol = S.KeyCol
OPTION (QUERYTRACEON 3604, -- Output info to client
        QUERYTRACEON 8619, -- Show applied optimization rules
        QUERYTRACEON 8620, -- Show rule-to-memo info
        QUERYTRACEON 8621, -- Show resulting tree
        QUERYTRACEON 2398, -- Show "smart seek costing"
        RECOMPILE );

আউটপুট থেকে আমরা দেখতে পাই যে direct- JOINআমাদের পেতে এই নিয়ম প্রয়োগ PhyOp_Rangeঅপারেটর: Rule Result: group=7 2 <SelIdxToRng>PhyOp_Range 1 ASC 2 (Distance = 2)। Subselect পরিবর্তে এই নিয়ম প্রয়োগ: Rule Result: group=9 2 <SelToIdxStrategy>PhyOp_Range 1 ASC 3 (Distance = 2)। আপনি এখানে প্রতিটি নিয়মের সাথে যুক্ত "স্মার্ট সিক কস্টিং" তথ্যও দেখেন। Direct- জন্য JOINএই আউটপুট (আমার জন্য) হল: Smart seek costing (7.2) :: 1.34078e+154 , 0.001। Subselect জন্য, এই আউটপুট হল: Smart seek costing (9.2) :: 1.34078e+154 , 1

শেষ পর্যন্ত, আমি অনেক উপসংহার করতে পারিনি - কিন্তু পলের উত্তর বেশিরভাগ ফাঁক বন্ধ করে দেয়। আমি স্মার্ট সন্ধান ব্যয় সম্পর্কিত আরও কিছু তথ্য দেখতে চাই।


4

এটি সত্যই কোনও উত্তর নয় - যেমনটি মিকেল উল্লেখ করেছেন, মন্তব্যগুলিতে এই সমস্যাটি নিয়ে আলোচনা করা কঠিন ...

মজার বিষয় হল, আপনি যদি সাবকোরিটিকে (select KeyCol FROM Target)একটি ইনলাইন টিভিএফ- তে রূপান্তর করেন তবে আপনি পরিকল্পনাটি এবং এর ব্যয়গুলি সাধারণ মূল ক্যোয়ারির মতোই দেখবেন:

CREATE FUNCTION dbo.cs_test()
RETURNS TABLE
WITH SCHEMABINDING
AS 
RETURN (
    SELECT KeyCol FROM dbo.Target
    );

/* "normal" variant */
SELECT S.KeyCol, s.OtherCol, T.KeyCol 
FROM staging AS S 
    LEFT OUTER JOIN Target AS T ON T.KeyCol = S.KeyCol;

/* "subquery" variant */
SELECT S.KeyCol, s.OtherCol, T.KeyCol 
FROM staging AS S 
    LEFT OUTER JOIN (SELECT KeyCol FROM Target) AS T ON T.KeyCol = S.KeyCol;

/* "inline-TVF" variant */
SELECT S.KeyCol, s.OtherCol, T.KeyCol 
FROM staging AS S 
    LEFT OUTER JOIN dbo.cs_test() t ON s.KeyCol = t.Keycol

ক্যোয়ারী পরিকল্পনা ( পেস্টেথপ্লান লিঙ্ক ):

এখানে চিত্র বর্ণনা লিখুন

ছাড়াই আমাকে বিশ্বাস করতে পরিচালিত করে যে ব্যয়বহুল ইঞ্জিন এই ধরণের সাবকোরিয়ামের যে পরিমাণ প্রভাব ফেলতে পারে তা সম্পর্কে বিভ্রান্ত ।

উদাহরণস্বরূপ, নিম্নলিখিত গ্রহণ করুন:

SELECT S.KeyCol, s.OtherCol, T.KeyCol 
FROM staging AS S 
    LEFT OUTER JOIN (
        SELECT KeyCol = CHECKSUM(NEWID()) 
        FROM Target
        ) AS T ON T.KeyCol = S.KeyCol;

কীভাবে আপনি যে খরচ? ক্যোয়ারী অপ্টিমাইজারটি উপরের "সাবকিউরি" বৈকল্পিকের সাথে খুব কম পরিকল্পনা বেছে নিয়েছে, তাতে একটি কম্পিউট স্কেলার ( পেস্টেথপ্লান ডটকম লিঙ্ক ) রয়েছে:

এখানে চিত্র বর্ণনা লিখুন

উপরের দেখানো "সাবকিউরি" বৈকল্পিকের তুলনায় গণনা স্কেলারটির আলাদা খরচ রয়েছে, তবে ক্যোরি অপ্টিমাইজারটি জানার কোনও উপায় নেই, এটি একটি প্রাক্কলন, ফিরে আসা সারিগুলির সংখ্যাটি কী হতে পারে। পরিকল্পনায় বাম বাহিরের জোড়ার জন্য একটি হ্যাশ ম্যাচ ব্যবহার করা হয়েছে যেহেতু সারি অনুমানটি অজানা এবং সুতরাং লক্ষ্য সারণিতে সারিগুলির সংখ্যাতে সেট করা।

এখানে চিত্র বর্ণনা লিখুন

মাইকেলে তার উত্তরে যে কাজটি করেছি তার সাথে আমি একমত হয়ে ছাড়া আমি এ থেকে বড় উপসংহার পাচ্ছি না এবং আমি আশাবাদী যে অন্য কেউ এর থেকে আরও ভাল উত্তর নিয়ে আসতে পারে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.