অ্যাজুর টেবিল স্টোরেজে পার্টিশনকি দিয়ে কীভাবে একটি ক্যোয়ারী গতিময় করবেন


10

কীভাবে আমরা এই ক্যোয়ারির গতি বাড়াব?

নিম্নলিখিত কোয়েরি কার্যকর করার সময়কালে আমাদের প্রায় 100 ভোক্তা রয়েছে1-2 minutes । এই রানগুলির প্রত্যেকটিই একটি গ্রাহক ক্রিয়াকলাপের 1 রান উপস্থাপন করে।

        TableQuery<T> treanslationsQuery = new TableQuery<T>()
         .Where(
          TableQuery.CombineFilters(
            TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, sourceDestinationPartitionKey)
           , TableOperators.Or,
            TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, anySourceDestinationPartitionKey)
          )
         );

এই ক্যোয়ারিতে প্রায় 5000 টি ফলাফল আসবে

সম্পূর্ণ কোড:

    public static async Task<IEnumerable<T>> ExecuteQueryAsync<T>(this CloudTable table, TableQuery<T> query) where T : ITableEntity, new()
    {
        var items = new List<T>();
        TableContinuationToken token = null;

        do
        {
            TableQuerySegment<T> seg = await table.ExecuteQuerySegmentedAsync(query, token);
            token = seg.ContinuationToken;
            items.AddRange(seg);
        } while (token != null);

        return items;
    }

    public static IEnumerable<Translation> Get<T>(string sourceParty, string destinationParty, string wildcardSourceParty, string tableName) where T : ITableEntity, new()
    {
        var acc = CloudStorageAccount.Parse(Environment.GetEnvironmentVariable("conn"));
        var tableClient = acc.CreateCloudTableClient();
        var table = tableClient.GetTableReference(Environment.GetEnvironmentVariable("TableCache"));
        var sourceDestinationPartitionKey = $"{sourceParty.ToLowerTrim()}-{destinationParty.ToLowerTrim()}";
        var anySourceDestinationPartitionKey = $"{wildcardSourceParty}-{destinationParty.ToLowerTrim()}";

        TableQuery<T> treanslationsQuery = new TableQuery<T>()
         .Where(
          TableQuery.CombineFilters(
            TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, sourceDestinationPartitionKey)
           , TableOperators.Or,
            TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, anySourceDestinationPartitionKey)
          )
         );

        var over1000Results = table.ExecuteQueryAsync(treanslationsQuery).Result.Cast<Translation>();
        return over1000Results.Where(x => x.expireAt > DateTime.Now)
                           .Where(x => x.effectiveAt < DateTime.Now);
    }

এই মৃত্যুদন্ড কার্যকর করার সময়, যখন 100 জন ভোক্তা থাকে, আপনি দেখতে পাচ্ছেন যে অনুরোধগুলি ক্লাস্টার হবে এবং স্পাইক তৈরি করবে:

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

এই স্পাইকগুলির সময়, অনুরোধগুলি প্রায় 1 মিনিটের বেশি সময় নেয়:

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

কীভাবে আমরা এই ক্যোয়ারির গতি বাড়াব?


5000 টি ফলাফল মনে হচ্ছে আপনি ক্যোয়ারিতে প্রায় যথেষ্ট ফিল্টার করছেন না। কোডটিতে কেবল 5000 টি ফলাফল স্থানান্তরিত করতে এক টন নেটওয়ার্ক সময় লাগবে। আপনি পরেও ফিল্টারিং করতে চলেছেন তা মনে করবেন না। | সর্বদা ক্যোয়ারিতে একটি প্রসেসিংয়ে যত বেশি ফাইলরটিং করা হয় তা করুন। আদর্শভাবে সারিগুলিতে যেগুলি একটি সূচক পেয়েছে এবং / অথবা কোনও গণিত দর্শনের ফলাফল।
ক্রিস্টোফার

"অনুবাদ" অবজেক্ট কি বড়? পুরো ডিবির মতো গেটিনের পরিবর্তে কিছু পরামিতি কেন আপনি পছন্দ করেন না?
হিরসওয়া ইউই

@ হিরসওয়াওয়ুই না তারা ছোট
l -'''''--------- '' '' '' '' ''

আপনার আরও ফিল্টারিং করা উচিত, 5000 টি ফলাফল টানা অর্থহীন বলে মনে হয়। আপনার ডেটা না জেনে বলা অসম্ভব, তবে আমি বলব যে আপনি এটি আরও অর্থবহ ফ্যাশনে ভাগ করার কোনও উপায় খুঁজে বের করতে বা ক্যোয়ারিতে কোনও প্রকারের ফিল্টারিংয়ের
প্রচলন করতে চান

কতগুলি পৃথক পার্টিশন আছে?
পিটার বনস

উত্তর:


3
  var over1000Results = table.ExecuteQueryAsync(treanslationsQuery).Result.Cast<Translation>();
        return over1000Results.Where(x => x.expireAt > DateTime.Now)
                           .Where(x => x.effectiveAt < DateTime.Now);

এখানে অন্যতম সমস্যা রয়েছে, আপনি ক্যোয়ারী চালাচ্ছেন এবং তারপরে এই "চাকা" ব্যবহার করে মেমরি থেকে ফিল্টার করছেন। ক্যোয়ারি চালুর আগে ফিল্টারগুলিতে সরিয়ে ফেলুন যা অনেক সাহায্য করবে।

দ্বিতীয়ত আপনাকে ডাটাবেস থেকে পুনরুদ্ধারের জন্য সারিগুলির কিছু সীমা সরবরাহ করতে হবে



3

এখানে 3 টি জিনিস আপনি বিবেচনা করতে পারেন:

। প্রথমত, Whereক্যোরির ফলাফলটিতে আপনি যে کلاসগুলি সম্পাদন করেন সেগুলি থেকে মুক্তি পান । ক্লোয়াসগুলিকে যথাসম্ভব কোয়ালিটিতে অন্তর্ভুক্ত করা ভাল (যদি আপনার টেবিলগুলিতে কোনও সূচক থাকে তবে সেগুলি আরও ভাল)। আপাতত, আপনি নীচে হিসাবে আপনার ক্যোয়ারী পরিবর্তন করতে পারেন:

var translationsQuery = new TableQuery<T>()
.Where(TableQuery.CombineFilters(
TableQuery.CombineFilters(
    TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, sourceDestinationPartitionKey),
    TableOperators.Or,
    TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, anySourceDestinationPartitionKey)
    ),
TableOperators.And,
TableQuery.CombineFilters(
    TableQuery.GenerateFilterConditionForDate("affectiveAt", QueryComparisons.LessThan, DateTime.Now),
    TableOperators.And,
    TableQuery.GenerateFilterConditionForDate("expireAt", QueryComparisons.GreaterThan, DateTime.Now))
));

আপনার কাছে পুনরুদ্ধার করতে প্রচুর পরিমাণে ডেটা থাকার কারণে আপনার প্রশ্নগুলি সমান্তরালে চালানো আরও ভাল। সুতরাং, আপনি স্টিফেন টুব সমান্তরাল উপর ভিত্তি করে লিখেছিলাম সঙ্গে do whileলুপ অভ্যন্তরীণ ExecuteQueryAsyncপদ্ধতি প্রতিস্থাপন করা উচিত । এইভাবে ক্যোয়ারি এক্সিকিউশন সময় হ্রাস পাবে। এটি একটি ভাল পছন্দ কারণ আপনি যখন এই পদ্ধতিতে কল করবেন তখন আপনি মুছে ফেলতে পারবেন , তবে এতে কিছুটা সীমাবদ্ধতা রয়েছে যা আমি কোডের এই অংশের পরে এ সম্পর্কে কথা বলব:Parallel.ForEachResult

public static IEnumerable<T> ExecuteQueryAsync<T>(this CloudTable table, TableQuery<T> query) where T : ITableEntity, new()
{
    var items = new List<T>();
    TableContinuationToken token = null;

    Parallel.ForEach(new InfinitePartitioner(), (ignored, loopState) =>
    {
        TableQuerySegment<T> seg = table.ExecuteQuerySegmented(query, token);
        token = seg.ContinuationToken;
        items.AddRange(seg);

        if (token == null) // It's better to change this constraint by looking at https://www.vivien-chevallier.com/Articles/executing-an-async-query-with-azure-table-storage-and-retrieve-all-the-results-in-a-single-operation
            loopState.Stop();
    });

    return items;
}

এবং তারপরে আপনি এটিকে আপনার Getপদ্ধতিতে কল করতে পারেন :

return table.ExecuteQueryAsync(translationsQuery).Cast<Translation>();

আপনি দেখতে পাচ্ছেন যে পদ্ধতিটি নিজেই অ্যাসিঙ্ক নয় (আপনার নামটি পরিবর্তন করা উচিত) এবং অ্যাসিঙ্ক পদ্ধতিতে Parallel.ForEachপাস করার সাথে সামঞ্জস্য নয়। আমি এর ExecuteQuerySegmentedপরিবর্তে ব্যবহার করেছি used কিন্তু, এটি আরো performant করতে এবং অ্যাসিঙ্ক্রোনাস পদ্ধতির উপকারিতা ব্যবহার করে আপনি উপরের প্রতিস্থাপন করতে ForEachসঙ্গে লুপ ActionBlockপদ্ধতি Dataflow বা ParallelForEachAsyncথেকে এক্সটেনশন পদ্ধতি AsyncEnumerator Nuget প্যাকেজ

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

। আমি নিশ্চিত না এটি একটি ভাল পরামর্শ বা না, তবে এটি করুন এবং ফলাফল দেখুন see এমএসডিএন-তে বর্ণিত হিসাবে :

সারণী পরিষেবাটি সার্ভারের সময়সীমাটি নিম্নলিখিতভাবে প্রয়োগ করে:

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

  • অপারেশনগুলি সন্নিবেশ করুন, আপডেট করুন এবং মুছুন: সর্বাধিক সময়সীমা বিরতি 30 সেকেন্ড। ত্রিশ সেকেন্ডও সমস্ত সন্নিবেশ, আপডেট এবং মুছে ফেলা ক্রিয়াকলাপগুলির জন্য ডিফল্ট ব্যবধান।

আপনি যদি কোনও সময়সীমা নির্দিষ্ট করে থাকেন যা পরিষেবার ডিফল্ট সময়সীমার চেয়ে কম, আপনার সময়সীমা ব্যবধান ব্যবহৃত হবে।

সুতরাং আপনি সময়সীমা নিয়ে খেলতে পারেন এবং কোনও কার্যকারিতা উন্নতি হয়েছে কিনা তা পরীক্ষা করতে পারেন check


2

দুর্ভাগ্যক্রমে, নীচে ক্যোয়ারী একটি পূর্ণ টেবিল স্ক্যান উপস্থাপন করেছে :

    TableQuery<T> treanslationsQuery = new TableQuery<T>()
     .Where(
      TableQuery.CombineFilters(
        TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, sourceDestinationPartitionKey)
       , TableOperators.Or,
        TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, anySourceDestinationPartitionKey)
      )
     );

আপনার এটি দুটি পার্টিশন কী ফিল্টারগুলিতে বিভক্ত করা উচিত এবং তাদের আলাদাভাবে জিজ্ঞাসা করা উচিত, যা দুটি বিভাজন স্ক্যান হয়ে যাবে এবং আরও দক্ষতার সাথে সম্পাদন করবে ।


আমরা এটির সাথে সম্ভবত 10% উন্নতি দেখেছি, তবে এটি পর্যাপ্ত নয়
l

1

সুতরাং গোপনীয়তা কেবল কোডেই নয় আপনার আজার স্টোরেজ টেবিলগুলি সেটআপ করার ক্ষেত্রেও রয়েছে।

ক) অ্যাজুরে আপনার প্রশ্নগুলির অনুকূলকরণের জন্য অন্যতম প্রধান বিকল্প হ'ল ক্যাচিং চালু করা। এটি আপনার সামগ্রিক প্রতিক্রিয়ার সময়গুলিকে তাত্পর্যপূর্ণভাবে হ্রাস করবে এবং এর মাধ্যমে আপনি উল্লেখ করেছেন এমন শীর্ষ সময়কালে বাধা অতিক্রম করবে।

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

আরও বিশদ এখানে দেখুন: https://docs.microsoft.com/en-us/azure/stores/tables/table-stores-design-for-query

আশাকরি এটা সাহায্য করবে.


-1

দ্রষ্টব্য: এটি সাধারণ ডিবি ক্যোয়ারী অপ্টিমাইজেশনের পরামর্শ।

এটি সম্ভব যে ORM বোকা কিছু করছে। অপ্টিমাইজেশানগুলি করার সময় কোনও বিমূর্ত স্তর নীচে নামানো ঠিক। তাই আমি কী চলছে তা দেখতে আরও সহজ করতে এবং অনুকূলিতকরণ আরও সহজ করার জন্য কোয়েরি ভাষার (এসকিউএল?) কোয়েরিতে পুনরায় লেখার পরামর্শ দিই।

অনুসন্ধানগুলি অনুকূলকরণের মূলটি বাছাই করা হচ্ছে! সাজানো টেবিল সাজানো প্রতিটি ক্যোয়ারিতে পুরো টেবিলটি স্ক্যান করার তুলনায় অনেক বেশি সস্তা! সুতরাং যদি সম্ভব হয় তবে ক্যোয়ারিতে ব্যবহৃত কী অনুসারে টেবিলটি সাজান রাখুন। বেশিরভাগ ডাটাবেস সমাধানে এটি একটি সূচক কী তৈরি করে অর্জন করা হয়।

আরও কয়েকটি কৌশল যা খুব কম সংমিশ্রণ থাকলে ভাল কাজ করে তা হ'ল প্রতিটি ক্যোয়ারিকে পৃথক (মেমরিতে অস্থায়ী) সারণী হিসাবে রাখতে হবে যা সর্বদা আপ টু ডেট থাকে। সুতরাং যখন কিছু inোকানো হয়, তখন এটি "ভিউ" টেবিলগুলিতে "sertedোকানো" হয়। কিছু ডাটাবেস সমাধান এটিকে "ভিউ" বলে।

আরও নিষ্ঠুর কৌশল লোড বিতরণের জন্য কেবল পঠনযোগ্য প্রতিরূপ তৈরি করা।

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