কীভাবে দক্ষতার সাথে একাধিক কলামে পরীক্ষা করা যায়?


26

এটি একটি বিষয় যা আমি পর্যায়ক্রমে বিরুদ্ধে এসেছি এবং এর পক্ষে এখনও ভাল সমাধান খুঁজে পাইনি।

নিম্নলিখিত সারণির কাঠামোটি মনে করি

CREATE TABLE T
(
A INT PRIMARY KEY,
B CHAR(1000) NULL,
C CHAR(1000) NULL
)

এবং প্রয়োজনীয়তাটি হ'ল নালামযোগ্য কলামগুলির মধ্যে কোনওটি নির্ধারণ করা উচিত Bবা Cআসলে কোনও NULLমান রয়েছে (এবং যদি তাই হয় তবে কোনটি (গুলি))।

এছাড়াও ধরে নিন যে টেবিলটিতে কয়েক মিলিয়ন সারি রয়েছে (এবং এই স্তরের ক্যোয়ারির আরও জেনেরিক সমাধানের জন্য আমি আগ্রহী বলে কোনও কলামের পরিসংখ্যান পাওয়া যায়নি যে তা উঁকি দেওয়া যায়)।

আমি এটি কাছে আসার কয়েকটি উপায় সম্পর্কে ভাবতে পারি তবে সবগুলিরই দুর্বলতা রয়েছে।

দুটি পৃথক EXISTSবিবৃতি। এই বন্ধ স্ক্যানিং শব্দতে গোড়ার দিকে যত তাড়াতাড়ি একটি সক্ষম হবেন সুবিধা হবে NULLপাওয়া যায়। তবে যদি উভয় কলামে বাস্তবে কোনও NULLগুলি থাকে তবে দুটি পূর্ণ স্ক্যানের ফলাফল হবে।

একক সমষ্টি অনুসন্ধান

SELECT 
    MAX(CASE WHEN B IS NULL THEN 1 ELSE 0 END) AS B,
    MAX(CASE WHEN C IS NULL THEN 1 ELSE 0 END) AS C
FROM T

এটি একই সাথে উভয় কলামে প্রক্রিয়া করতে পারে সুতরাং একটি পূর্ণ স্ক্যানের সবচেয়ে খারাপ ক্ষেত্রে। অসুবিধাটি হ'ল এমনকি যদি এটি NULLখুব প্রথম দিকে উভয় কলামে মুখোমুখি হয় তবে এখনও টেবিলের বাকী পুরো অংশটি স্ক্যান করে শেষ করা হবে।

ব্যবহারকারী ভেরিয়েবল

আমি এটি করার একটি তৃতীয় উপায় সম্পর্কে ভাবতে পারি

BEGIN TRY
DECLARE @B INT, @C INT, @D INT

SELECT 
    @B = CASE WHEN B IS NULL THEN 1 ELSE @B END,
    @C = CASE WHEN C IS NULL THEN 1 ELSE @C END,
    /*Divide by zero error if both @B and @C are 1.
    Might happen next row as no guarantee of order of
    assignments*/
    @D = 1 / (2 - (@B + @C))
FROM T  
OPTION (MAXDOP 1)       
END TRY
BEGIN CATCH
IF ERROR_NUMBER() = 8134 /*Divide by zero*/
    BEGIN
    SELECT 'B,C both contain NULLs'
    RETURN;
    END
ELSE
    RETURN;
END CATCH

SELECT ISNULL(@B,0),
       ISNULL(@C,0)

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

উপরোক্ত পদ্ধতির শক্তিকে একত্রিত করে এমন কি আরও একটি বিকল্প রয়েছে?

সম্পাদন করা

কেবলমাত্র এ পর্যন্ত জমা দেওয়া উত্তরের জন্য পড়ার পরিপ্রেক্ষিতে প্রাপ্ত ফলাফলের সাথে এটি আপডেট করতে (@ ইয়পারকিউবের পরীক্ষার ডেটা ব্যবহার করে)

+----------+------------+------+---------+----------+----------------------+----------+------------------+
|          | 2 * EXISTS | CASE | Kejser  |  Kejser  |        Kejser        | ypercube |       8kb        |
+----------+------------+------+---------+----------+----------------------+----------+------------------+
|          |            |      |         | MAXDOP 1 | HASH GROUP, MAXDOP 1 |          |                  |
| No Nulls |      15208 | 7604 |    8343 | 7604     | 7604                 |    15208 | 8346 (8343+3)    |
| One Null |       7613 | 7604 |    8343 | 7604     | 7604                 |     7620 | 7630 (25+7602+3) |
| Two Null |         23 | 7604 |    8343 | 7604     | 7604                 |       30 | 30 (18+12)       |
+----------+------------+------+---------+----------+----------------------+----------+------------------+

@ থমাস এর উত্তর আমি পরিবর্তন জন্য TOP 3করতে TOP 2আগেই থেকে প্রস্থান করার জন্য সম্ভাব্য অনুমতি দেয়। আমি উত্তরটির জন্য পূর্বনির্ধারিতভাবে একটি সমান্তরাল পরিকল্পনা পেয়েছি তাই MAXDOP 1অন্যান্য পরিকল্পনার সাথে পাঠ্যের সংখ্যা আরও তুলনীয় করার জন্য একটি ইঙ্গিত দিয়ে চেষ্টা করেছি । আমার আগের পরীক্ষার মতো ফলাফলগুলি দেখে আমি কিছুটা অবাক হয়েছিলাম পুরো টেবিলটি না পড়ে query কোয়েরি শর্ট সার্কিটটি দেখেছি।

শর্ট সার্কিটগুলির নীচে আমার পরীক্ষার ডেটার জন্য পরিকল্পনা

শর্ট সার্কিট

ইপারকিউবের ডেটার পরিকল্পনা রয়েছে

শর্টসার্কিট নয়

সুতরাং এটি পরিকল্পনায় একটি ব্লকিং বাছাই করা অপারেটর যুক্ত করে। আমি HASH GROUPইঙ্গিত দিয়ে চেষ্টাও করেছি তবে এটি এখনও সমস্ত সারিটি পড়া শেষ করে

শর্টসার্কিট নয়

সুতরাং মূল hash match (flow distinct)বিকল্পটি অন্য বিকল্পগুলি যে কোনওভাবে ব্লক করে এবং সমস্ত সারি গ্রাস করবে বলে শর্ট সার্কিটের জন্য এই পরিকল্পনার অনুমতি দেওয়ার জন্য কোনও অপারেটরকে পাওয়া উচিত বলে মনে হয় । আমি মনে করি না এটি নির্দিষ্টভাবে জোর করার কোনও ইঙ্গিত রয়েছে তবে স্পষ্টতই "সাধারণভাবে, অপটিমাইজার একটি ফ্লো ডিসস্টিন্ট বেছে নেয় যেখানে এটি নির্ধারণ করে যে ইনপুট সেটে স্বতন্ত্র মানগুলির চেয়ে কম আউটপুট সারি প্রয়োজন are"

@ ইপারকিউবের ডেটাতে প্রতিটি কলামে NULLমানগুলি (সারণী কার্ডিনালিটি = 30300) সহ কেবল 1 টি সারি থাকে এবং অপারেটরের ভিতরে এবং বাইরে যাওয়া আনুমানিক সারি উভয়ই 1। শিকারটিকে অপটিমাইজারের কাছে আরও কিছুটা অস্বচ্ছ করে ফ্লো ডিস্টিন্ট অপারেটরের সাথে একটি পরিকল্পনা তৈরি করে।

SELECT TOP 2 *
FROM (SELECT DISTINCT 
        CASE WHEN b IS NULL THEN NULL ELSE 'foo' END AS b
      , CASE WHEN c IS NULL THEN NULL ELSE 'bar' END AS c
  FROM test T 
  WHERE LEFT(b,1) + LEFT(c,1) IS NULL
) AS DT 

সম্পাদনা 2

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

SELECT DISTINCT TOP 2 NullExists
FROM test T 
CROSS APPLY (VALUES(CASE WHEN b IS NULL THEN 'b' END),
                   (CASE WHEN c IS NULL THEN 'c' END)) V(NullExists)
WHERE NullExists IS NOT NULL

ভবিষ্যদ্বাণী করাটি সম্ভবত এটির চেয়ে ভাল WHERE (b IS NULL OR c IS NULL) AND NullExists IS NOT NULLতবে আগের পরীক্ষার ডেটার বিপরীতে যে আমাকে ফ্লো ডিসস্টিন্টের সাথে কোনও পরিকল্পনা দেয় না, যেখানে NullExists IS NOT NULLএকটি করে (নীচে পরিকল্পনা করে)।

Unpivoted

উত্তর:


20

কেমন:

SELECT TOP 3 *
FROM (SELECT DISTINCT 
        CASE WHEN B IS NULL THEN NULL ELSE 'foo' END AS B
        , CASE WHEN C IS NULL THEN NULL ELSE 'bar' END AS C
  FROM T 
  WHERE 
    (B IS NULL AND C IS NOT NULL) 
    OR (B IS NOT NULL AND C IS NULL) 
    OR (B IS NULL AND C IS NULL)
) AS DT

আমি এই পদ্ধতির পছন্দ। আমার সম্ভাব্য কয়েকটি সমস্যা আছে যা আমি আমার প্রশ্নের সম্পাদনায় প্রকাশ করি। লিখিত হিসাবে TOP 3মাত্র হতে পারে TOP 2না হওয়া পর্যন্ত নিম্নলিখিত প্রতিটি এক খুঁজে বের এটা স্ক্যান করবে বর্তমানে (NOT_NULL,NULL), (NULL,NOT_NULL), (NULL,NULL)। এই 3 টির মধ্যে 2 টিও যথেষ্ট হবে - এবং এটি যদি (NULL,NULL)প্রথমটি খুঁজে পায় তবে দ্বিতীয়টিরও প্রয়োজন হবে না। এছাড়াও শর্ট সার্কিট করার জন্য পরিকল্পনা একটি মাধ্যমে স্বতন্ত্র বাস্তবায়ন করতে হবে hash match (flow distinct)বরং অপারেটর hash match (aggregate)বাdistinct sort
মার্টিন স্মিথ

6

আমি যেমন প্রশ্নটি বুঝতে পারি, আপনি জানতে চান যে কোনও কলামের মানগুলিতে শূন্য রয়েছে যা বি বা সি ন্যূনতম যে সারিগুলি প্রকৃতপক্ষে ফিরে আসার বিপরীতে রয়েছে whether যদি এটি হয়, তবে কেন না:

Select Top 1 'B as nulls' As Col
From T
Where T.B Is Null
Union All
Select Top 1 'C as nulls'
From T
Where T.C Is Null

এসকিউএল ২০০৮ আর ২ এবং এক মিলিয়ন সারিগুলির সাথে আমার পরীক্ষার ছদ্মবেশে আমি ক্লায়েন্ট স্ট্যাটিস্টিকস ট্যাব থেকে এমএসে নিম্নলিখিত ফলাফল পেয়েছি:

Kejser                          2907,2875,2829,3576,3103
ypercube                        2454,1738,1743,1765,2305
OP single aggregate solution    (stopped after 120,000 ms) Wouldn't even finish
My solution                     1619,1564,1665,1675,1674

আপনি যদি নলক ইঙ্গিতটি যোগ করেন তবে ফলাফল আরও দ্রুত:

Select Top 1 'B as nulls' As Col
From T With(Nolock)
Where T.B Is Null
Union All
Select Top 1 'C as nulls'
From T With(Nolock)
Where T.C Is Null

My solution (with nolock)       42,70,94,138,120

রেফারেন্সের জন্য আমি ডেটা উত্পন্ন করতে রেড-গেটের এসকিউএল জেনারেটর ব্যবহার করেছি। আমার এক মিলিয়ন সারিগুলির মধ্যে, 9,886 সারিগুলির নাল বি মান এবং 10,019 এর নাল সি মান ছিল।

এই সিরিজের পরীক্ষায়, বি কলামের প্রতিটি সারির একটি মান থাকে:

Kejser                          245200  Scan count 1, logical reads 367259, physical reads 858, read-ahead reads 367278
                                250540  Scan count 1, logical reads 367259, physical reads 860, read-ahead reads 367280

ypercube(1)                     249137  Scan count 2, logical reads 367276, physical reads 850, read-ahead reads 367278
                                248276  Scan count 2, logical reads 367276, physical reads 869, read-ahead reads 368765

My solution                     250348  Scan count 2, logical reads 367276, physical reads 858, read-ahead reads 367278
                                250327  Scan count 2, logical reads 367276, physical reads 854, read-ahead reads 367278

প্রতিটি পরীক্ষার আগে (উভয় সেট) আমি দৌড়েছি CHECKPOINTএবং DBCC DROPCLEANBUFFERS

টেবিলে কোনও নাল নেই এমন এখানে ফলাফল রয়েছে। মনে রাখবেন যে ইপারক्यूब দ্বারা সরবরাহিত 2 টি বিদ্যমান সমাধানটি পড়ার এবং সম্পাদনের সময়কার ক্ষেত্রে আমার সাথে প্রায় অভিন্ন। অ্যাডভান্সড স্ক্যানিং ব্যবহারের এন্টারপ্রাইজ / বিকাশকারী সংস্করণের সুবিধার কারণে এটি (আমরা) বিশ্বাস করি । আপনি যদি কেবলমাত্র স্ট্যান্ডার্ড সংস্করণ বা নিম্ন ব্যবহার করে থাকেন তবে কেজারের দ্রবণটি খুব দ্রুততম সমাধান হতে পারে।

Kejser                          248875  Scan count 1, logical reads 367259, physical reads 860, read-ahead reads 367290

ypercube(1)                     243349  Scan count 2, logical reads 367265, physical reads 851, read-ahead reads 367278
                                242729  Scan count 2, logical reads 367265, physical reads 858, read-ahead reads 367276
                                242531  Scan count 2, logical reads 367265, physical reads 855, read-ahead reads 367278

My solution                     243094  Scan count 2, logical reads 367265, physical reads 857, read-ahead reads 367278
                                243444  Scan count 2, logical reads 367265, physical reads 857, read-ahead reads 367278

4

করছেন IFবিবৃতি দেয়া?

এটি আপনাকে সারণির মধ্য দিয়ে এক পাসে বি বা সি এর অস্তিত্ব নিশ্চিত করতে দেয়:

DECLARE 
  @A INT, 
  @B CHAR(10), 
  @C CHAR(10)

SET @B = 'X'
SET @C = 'X'

SELECT TOP 1 
  @A = A, 
  @B = B, 
  @C = C
FROM T 
WHERE B IS NULL OR C IS NULL 

IF @@ROWCOUNT = 0 
BEGIN 
  SELECT 'No nulls'
  RETURN
END

IF @B IS NULL AND @C IS NULL
BEGIN
  SELECT 'Both null'
  RETURN
END 

IF @B IS NULL 
BEGIN
  SELECT TOP 1 
    @C = C
  FROM T
  WHERE A > @A
  AND C IS NULL

  IF @B IS NULL AND @C IS NULL 
  BEGIN
    SELECT 'Both null'
    RETURN
  END
  ELSE
  BEGIN
    SELECT 'B is null'
    RETURN
  END
END

IF @C IS NULL 
BEGIN
  SELECT TOP 1 
    @B = B
  FROM T 
  WHERE A > @A
  AND B IS NULL

  IF @C IS NULL AND @B IS NULL
  BEGIN
    SELECT 'Both null'
    RETURN
  END
  ELSE
  BEGIN
    SELECT 'C is null'
    RETURN
  END
END      

4

: সংস্করণে এসকিউএল বেহালার পরীক্ষিত 2008 R2 এবং 2012 30K সারি সঙ্গে।

  • EXISTSক্যোয়ারী শো দক্ষতা বিপুল সুবিধা যখন এটি NULLs গোড়ার দিকে খুঁজে বের করে - যা আশা করা হচ্ছে।
  • আমি EXISTSক্যোয়ারির সাথে আরও ভাল পারফরম্যান্স পেয়েছি - ২০১২ সালে সমস্ত ক্ষেত্রে, যা আমি ব্যাখ্যা করতে পারি না।
  • 2008R2-এ, যখন কোনও নাল নেই, তখন এটি অন্য 2 টি প্রশ্নের চেয়ে ধীর। এটি যত তাড়াতাড়ি নুলগুলি খুঁজে পাবে, তত দ্রুত তা দ্রুত হয় এবং যখন উভয় কলামে নালগুলি প্রারম্ভিক হয় তখন এটি অন্য 2 টি প্রশ্নের থেকে অনেক দ্রুত।
  • টমাস কেজারের জিজ্ঞাসাটি মার্টিনের CASEপ্রশ্নের তুলনায় ২০১২-এর তুলনায় কিছুটা হলেও ধারাবাহিকভাবে ভাল এবং ২০০৮ -২ এর চেয়ে খারাপ বলে মনে হচ্ছে ।
  • 2012 সংস্করণে আরও ভাল পারফরম্যান্স রয়েছে বলে মনে হয়। এটি এসকিউএল-ফিডল সার্ভারগুলির সেটিংসের সাথে করতে পারে তবে কেবল অপটিমাইজারের উন্নতি নয়।

প্রশ্ন এবং সময়। সময় যেখানে হয়েছে:

  • কোন নালসের সাথে 1 ম
  • কলাম সহ 2nd Bএক থাকার NULLএকটি ছোট এ id
  • উভয় কলামের সাথে NULLছোট আইডিতে একটি করে রয়েছে 3 তম।

এখানে আমরা যাচ্ছি (পরিকল্পনাগুলিতে কোনও সমস্যা আছে, আমি পরে আবার চেষ্টা করব now আপাতত লিঙ্কগুলি অনুসরণ করুন):


2 টি EXISS উপকোয়্যারীর সাথে প্রশ্ন

SELECT 
      CASE WHEN EXISTS (SELECT * FROM test WHERE b IS NULL)
             THEN 1 ELSE 0 
      END AS B,
      CASE WHEN EXISTS (SELECT * FROM test WHERE c IS NULL)
             THEN 1 ELSE 0 
      END AS C ;

-------------------------------------
Times in ms (2008R2): 1344 - 596 -  1  
Times in ms   (2012):   26 -  14 -  2

মার্টিন স্মিথের একক সমষ্টি ক্যোয়ারী

SELECT 
    MAX(CASE WHEN b IS NULL THEN 1 ELSE 0 END) AS B,
    MAX(CASE WHEN c IS NULL THEN 1 ELSE 0 END) AS C
FROM test ;

--------------------------------------
Times in ms (2008R2):  558 - 553 - 516  
Times in ms   (2012):   37 -  35 -  36

টমাস কেজারের জিজ্ঞাসা

SELECT TOP 3 *
FROM (SELECT DISTINCT 
        CASE WHEN B IS NULL THEN NULL ELSE 'foo' END AS b
      , CASE WHEN C IS NULL THEN NULL ELSE 'bar' END AS c
  FROM test T 
  WHERE 
    (B IS NULL AND C IS NOT NULL) 
    OR (B IS NOT NULL AND C IS NULL) 
    OR (B IS NULL AND C IS NULL)
) AS DT ;

--------------------------------------
Times in ms (2008R2):  859 - 705 - 668  
Times in ms   (2012):   24 -  19 -  18

আমার পরামর্শ (1)

WITH tmp1 AS
  ( SELECT TOP (1) 
        id, b, c
    FROM test
    WHERE b IS NULL OR c IS NULL
    ORDER BY id 
  ) 

  SELECT 
      tmp1.*, 
      NULL AS id2, NULL AS b2, NULL AS c2
  FROM tmp1
UNION ALL
  SELECT *
  FROM
    ( SELECT TOP (1)
          tmp1.id, tmp1.b, tmp1.c,
          test.id AS id2, test.b AS b2, test.c AS c2 
      FROM test
        CROSS JOIN tmp1
      WHERE test.id >= tmp1.id
        AND ( test.b IS NULL AND tmp1.c IS NULL
           OR tmp1.b IS NULL AND test.c IS NULL
            )
      ORDER BY test.id
    ) AS x ;

--------------------------------------
Times in ms (2008R2): 1089 - 572 -  16   
Times in ms   (2012):   28 -  15 -   1

এটিতে আউটপুটটিতে কিছু মসৃণতা প্রয়োজন তবে দক্ষতা EXISTSক্যোয়ারের মতো। আমি ভেবেছিলাম যখন নালাগুলি না থাকলে এটি আরও ভাল হবে তবে টেস্টগুলি দেখায় যে এটি তা নয়।


পরামর্শ (2)

যুক্তিটি সহজ করার চেষ্টা করছেন:

CREATE TABLE tmp
( id INT
, b CHAR(1000)
, c CHAR(1000)
) ;

DELETE  FROM tmp ;

INSERT INTO tmp 
    SELECT TOP (1) 
        id, b, c
    FROM test
    WHERE b IS NULL OR c IS NULL
    ORDER BY id  ; 

INSERT INTO tmp 
    SELECT TOP (1)
        test.id, test.b, test.c 
      FROM test
        JOIN tmp 
          ON test.id >= tmp.id
      WHERE ( test.b IS NULL AND tmp.c IS NULL
           OR tmp.b IS NULL AND test.c IS NULL
            )
      ORDER BY test.id ;

SELECT *
FROM tmp ;

এটি আগের পরামর্শের চেয়ে 2008R2 তে আরও ভাল পারফর্মেন্স বলে মনে হচ্ছে তবে 2012 এর চেয়ে খারাপ (সম্ভবত ২ য় কেবি এর উত্তর মত ২ য় পঠনটি আবারও INSERTলেখা যেতে পারে IF):

------------------------------------------
Times in ms (2008R2): 416+6 - 1+127 -  1+1   
Times in ms   (2012):  14+1 - 0+27  -  0+29

0

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

আপনি যখন 2 টি কলামকে একত্রীকরণ করেন এবং কোনও শূন্য হয় তবে ফলাফলটি শূন্য হবে

যেমন

null + 'a' = null

সুতরাং এই কোডটি চেক করুন

IF EXISTS (SELECT 1 FROM T WHERE B+C is null)
SELECT Top 1 ISNULL(B,'B ') + ISNULL(C,'C') as [Nullcolumn] FROM T WHERE B+C is null

-3

কেমন:

select 
    exists(T.B is null) as 'B is null',
    exists(T.C is null) as 'C is null'
from T;

যদি এটি কাজ করে (আমি এটি পরীক্ষা করিনি) তবে এটি দুটি কলাম সহ এক-সারি টেবিল উপস্থাপন করতে পারে, প্রত্যেকে সত্যই বা মিথ্যা। আমি দক্ষতা পরীক্ষা করিনি।


2
এটি অন্য কোনও ডিবিএমএসে বৈধ হলেও আমি সন্দেহ করি যে এর সঠিক শব্দার্থবিজ্ঞান রয়েছে। ধরে নিই যে T.B is nullএটি বুলিয়ান ফলাফল হিসাবে বিবেচিত হবে EXISTS(SELECT true)এবং EXISTS(SELECT false)উভয়ই সত্যই ফিরে আসবে। এই মাইএসকিউএল উদাহরণটি ইঙ্গিত দেয় যে উভয় কলামে নুল থাকে যখন বাস্তবে না হয়
মার্টিন স্মিথ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.