সত্তা ফ্রেমওয়ার্ক Inোকানোর দ্রুততম উপায়


682

সত্তা ফ্রেমওয়ার্কে প্রবেশের দ্রুততম উপায়টি আমি সন্ধান করছি।

আমি যেখানে আপনার সক্রিয় ট্রানজেকশনস্কোপ এবং সন্নিবেশ বিশাল (4000+) রয়েছে সেই দৃশ্যের কারণে আমি এটি জিজ্ঞাসা করছি। এটি সম্ভাব্য 10 মিনিটেরও বেশি সময় ধরে থাকতে পারে (লেনদেনের ডিফল্ট সময়সীমা) এবং এটি অসম্পূর্ণ লেনদেনের দিকে পরিচালিত করে।


1
আপনি বর্তমানে এটি কীভাবে করছেন?
ডাস্টিন লাইন

লেনদেনস্কোপ তৈরি করা, ডিবিসিঙ্কটেক্সট তাত্ক্ষণিকভাবে সংযোগ খোলা এবং প্রতিটি বিবৃতিতে সন্নিবেশ এবং সেভিংসচেঞ্জগুলি (প্রতিটি রেকর্ডের জন্য) করা, দ্রষ্টব্য: ট্রানজেকশনস্কোপ এবং ডিবিসিঙ্কটেক্সট বিবৃতি ব্যবহার করছে এবং শেষ পর্যন্ত সংযোগটি বন্ধ করছি ব্লক
বঙ্গো শার্প

জন্য রেফারেন্স আরেকটি উত্তর: stackoverflow.com/questions/5798646/...
Ladislav Mrnka

2
এসকিউএল ডাটাবেসে সন্নিবেশ করার দ্রুততম উপায় EF জড়িত না। আফিক তার বিসিপি তখন টিভিপি + মার্জ / sertোকান।
স্টিংজি জ্যাক

1
যারা মন্তব্য পড়বেন তাদের জন্য: সর্বাধিক প্রযোজ্য, আধুনিক উত্তর এখানে।
তানভীর বদর

উত্তর:


986

আপনার প্রশ্নের মন্তব্যে আপনার মন্তব্যে:

"... সেভিং চেঞ্জস ( প্রতিটি রেকর্ডের জন্য ) ..."

এটি আপনি করতে পারেন সবচেয়ে খারাপ জিনিস! SaveChanges()প্রতিটি রেকর্ডের জন্য কল করা বাল্ক সন্নিবেশকে খুব নিচে করে। আমি কয়েকটি সাধারণ পরীক্ষা করবো যা খুব সম্ভবত কার্য সম্পাদনকে উন্নত করবে:

  • SaveChanges()সমস্ত রেকর্ড পরে একবার কল করুন ।
  • SaveChanges()উদাহরণস্বরূপ 100 রেকর্ডের পরে কল করুন ।
  • SaveChanges()উদাহরণস্বরূপ 100 টি রেকর্ডের পরে কল করুন এবং প্রসঙ্গটি নিষ্পত্তি করুন এবং একটি নতুন তৈরি করুন।
  • পরিবর্তন সনাক্তকরণ অক্ষম করুন

বাল্ক সন্নিবেশগুলির জন্য আমি এই জাতীয় প্যাটার্ন নিয়ে কাজ করছি এবং পরীক্ষা করছি:

using (TransactionScope scope = new TransactionScope())
{
    MyDbContext context = null;
    try
    {
        context = new MyDbContext();
        context.Configuration.AutoDetectChangesEnabled = false;

        int count = 0;            
        foreach (var entityToInsert in someCollectionOfEntitiesToInsert)
        {
            ++count;
            context = AddToContext(context, entityToInsert, count, 100, true);
        }

        context.SaveChanges();
    }
    finally
    {
        if (context != null)
            context.Dispose();
    }

    scope.Complete();
}

private MyDbContext AddToContext(MyDbContext context,
    Entity entity, int count, int commitCount, bool recreateContext)
{
    context.Set<Entity>().Add(entity);

    if (count % commitCount == 0)
    {
        context.SaveChanges();
        if (recreateContext)
        {
            context.Dispose();
            context = new MyDbContext();
            context.Configuration.AutoDetectChangesEnabled = false;
        }
    }

    return context;
}

আমার একটি পরীক্ষার প্রোগ্রাম রয়েছে যা 560.000 সত্তা (9 স্কেলার বৈশিষ্ট্য, কোনও নেভিগেশন সম্পত্তি নয়) ডিবিতে প্রবেশ করে। এই কোডটি দিয়ে এটি 3 মিনিটেরও কম সময়ে কাজ করে।

পারফরম্যান্সের জন্য SaveChanges()"বহু" রেকর্ডের পরে কল করা গুরুত্বপূর্ণ ("অনেকগুলি" প্রায় 100 বা 1000)। এটি SaveChanges এর পরে প্রসঙ্গটি নিষ্পত্তি করতে এবং একটি নতুন তৈরি করার জন্য কর্মক্ষমতা উন্নত করে। এটি সমস্ত এনটাইটস থেকে প্রসঙ্গটি সাফ করে, এটি SaveChangesকরে না, সত্তা এখনও রাজ্যে প্রসঙ্গে সংযুক্ত রয়েছে Unchanged। এটি প্রসঙ্গে সংযুক্ত সংস্থাগুলির ক্রমবর্ধমান আকার যা সন্নিবেশের ধাপে ধাপে ধীর করে দেয়। সুতরাং, কিছু সময় পরে এটি সাফ করা সহায়ক।

আমার 560000 সত্তার জন্য এখানে কয়েকটি পরিমাপ রয়েছে:

  • কমিটকাউন্ট = 1, পুনরায় তৈরি করুন কনটেক্সট = মিথ্যা: অনেক ঘন্টা (এটি আপনার বর্তমান পদ্ধতি)
  • কমিটকাউন্ট = 100, রিরিকেটকন্টেক্সট = ভুয়া: 20 মিনিটেরও বেশি
  • কমিটকাউন্ট = 1000, রিসারেটকন্টেক্সট = ভুয়া: 242 সেকেন্ড
  • কমিটকাউন্ট = 10000, রিসারেটকন্টেক্সট = ভুয়া: 202 সেকেন্ড
  • কমিটকাউন্ট = 100000, রিসারেটকন্টেক্সট = ভুয়া: 199 সেকেন্ড
  • কমিটকাউন্ট = 1000000, রিসারেটকন্টেক্সট = ভুয়া: মেমরির ব্যতিক্রম
  • কমিটকাউন্ট = 1, পুনরুদ্ধারকন্টেক্সট = সত্য: 10 মিনিটেরও বেশি
  • কমিটকাউন্ট = 10, পুনরুদ্ধারকন্টেক্সট = সত্য: 241 সেকেন্ড
  • কমিটকাউন্ট = 100, রিরিকেট কনটেক্সট = সত্য: 164 সেকেন্ড
  • কমিটকাউন্ট = 1000, রিরিকেটকন্টেক্সট = সত্য: 191 সেকেন্ড

উপরের প্রথম পরীক্ষায় আচরণটি হ'ল পারফরম্যান্সটি খুব অ-রৈখিক এবং সময়ের সাথে সাথে অত্যন্ত হ্রাস পায়। ("অনেক ঘন্টা" একটি অনুমান, আমি এই পরীক্ষাটি কখনই শেষ করি না, আমি 20 মিনিটের পরে 50.000 সত্তা থেকে থামিয়ে দিয়েছি)) অন্য সমস্ত পরীক্ষায় এই অ-রৈখিক আচরণ এত তাৎপর্যপূর্ণ নয়।


89
@ বনগো শার্প: ডিবি কনটেক্সটে সেট করতে ভুলবেন না AutoDetectChangesEnabled = false;। : এটা একটি বড় অতিরিক্ত কর্মক্ষমতা প্রভাব রয়েছে stackoverflow.com/questions/5943394/...
Slauma

6
হ্যাঁ, সমস্যাটি হ'ল আমি সত্ত্বা ফ্রেমওয়ার্ক 4 ব্যবহার করছি এবং অটোডিটেক্ট চ্যাঞ্জসইনবেলড ৪.১ এর একটি অংশ, তবুও, আমি পারফরম্যান্স টেস্ট করেছি এবং আমার বিস্ময়কর ফলাফল ছিল, এটি 00:12:00 থেকে 00:00:22 এ চলে গেছে প্রতিটি সত্তা ওভারভারলোড করছিল ... আপনার উত্তরওয়ালার জন্য অনেক ধন্যবাদ! এটি আমি যা খুঁজছিলাম
বঙ্গো শার্প

10
প্রসঙ্গের জন্য আপনাকে ধন্যবাদ। কনফিগারেশন.আউটু ডিটেক্টট চেঞ্জস এনেবলড = মিথ্যা; টিপ, এটি একটি বিশাল পার্থক্য করে।
ডগল্যাজ

1
@ ডাহাকের ৯৯: আপনি কি সঠিক সংস্করণ EF> = 4.1 ব্যবহার করছেন DbContext, না ObjectContext?
স্লুমা

3
@ ডাহাকের ৯৯: আমি পরামর্শ দিচ্ছি যে আপনি সম্ভবত আরও বিশদ নিয়ে আপনার সমস্যার জন্য একটি পৃথক প্রশ্ন তৈরি করুন। আমি কী ভুল তা এখানে বের করতে পারছি না।
স্লুমা

176

এই সংমিশ্রণটি যথেষ্ট গতি বাড়ায়।

context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;

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

1
আমার পরীক্ষায় 20.000 সারি 101 সেকেন্ড থেকে 88 সেকেন্ডে নেমে গেছে। অনেক কিছুই নয় এবং এর কী কী প্রভাব পড়তে পারে।
এএইচ।

27
@ জেরেমি কুক আমি মনে করি আপনি যা পেতে চাইছেন তা এই উত্তরটি আরও ভাল হবে যদি এটি তাদের বৈশিষ্ট্যগুলিকে তাদের ডিফল্ট মানগুলি (পারফরম্যান্সের উন্নতি বাদ দিয়ে) থেকে পরিবর্তন করার সম্ভাব্য প্রভাবগুলি ব্যাখ্যা করে। আমি রাজী.
সিউডোকোডার

1
এটি আমার পক্ষে কাজ করেছে, যদিও আপনি যদি প্রসঙ্গে রেকর্ডগুলি আপডেট করেন তবে আপনাকে অবশ্যই ডিটেক্ট চেঞ্জস () স্পষ্টভাবে কল করতে হবে
পাহাড়ের স্তুক

2
এই অক্ষম করা যেতে পারে এবং তারপর একটি ব্যবহার করে দেখুন-পরিশেষে ব্লক সঙ্গে পুনরায় সক্রিয়: msdn.microsoft.com/en-us/data/jj556205.aspx
yellavon

98

সবচেয়ে দ্রুততম উপায়টি হ'ল বাল্ক সন্নিবেশ এক্সটেনশনটি ব্যবহার করা হবে , যা আমি বিকাশ করেছি

দ্রষ্টব্য: এটি একটি বাণিজ্যিক পণ্য, বিনা মূল্যে নয়

এটি সর্বাধিক পারফরম্যান্স পেতে স্কেলবুলকপি এবং কাস্টম ডেটারিডার ব্যবহার করে। ফলস্বরূপ এটি নিয়মিত সন্নিবেশ বা অ্যাডরেঞ্জ ব্যবহারের চেয়ে 20 গুণ বেশি দ্রুত ইন্টিফ্রেমওয়ার্ক.বুল্কইনসেট বনাম ইএফ অ্যাড্রেঞ্জ

ব্যবহার অত্যন্ত সহজ

context.BulkInsert(hugeAmountOfEntities);

10
দ্রুত তবে কেবল শ্রেণিবিন্যাসের উপরের স্তরটি করে।
সিএডি 4

65
এটি নিখরচায় নয়।
আমির সানিয়ান

72
বিজ্ঞাপনগুলি আরও স্মার্ট হয়ে উঠছে ... এটি অর্থ প্রদান করা পণ্য এবং ফ্রিল্যান্সের জন্য অত্যন্ত ব্যয়বহুল। সতর্ক করা হবে!
জুলিউকিউ

35
1 বছরের সহায়তা এবং আপগ্রেডের জন্য USD600? তুমি কি তোমার সিদ্ধান্ত থেকে সরে গেছো?
ক্যামিলো তেরেভিনতো

7
আমি আর পণ্যটির মালিক নই
ম্যাক্সেলগো

83

আপনি এটির System.Data.SqlClient.SqlBulkCopyজন্য ব্যবহার করা উচিত । এখানে ডকুমেন্টেশন রয়েছে এবং অবশ্যই অনলাইনে প্রচুর টিউটোরিয়াল রয়েছে।

দুঃখিত, আমি জানি আপনি EF যা চান তা করার জন্য একটি সহজ উত্তর খুঁজছিলেন, তবে বাল্ক অপারেশনগুলি ওআরএম বলতে যা বোঝায় তা আসলে নয়।


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

7
আমি সরাসরি আমার অ্যাপ্লিকেশন থেকে প্রচুর পরিমাণে তথ্য সন্নিবেশ করানোর জন্য স্কেলবুল্ককপি ব্যবহার করেছি। আপনাকে মূলত একটি ডেটা টেবিল তৈরি করতে হবে, এটি পূরণ করতে হবে এবং তারপরে এটি বাল্ককপিতে প্রেরণ করতে হবে। আপনি যখন আপনার
ডেটা টেবিলটি

2
আমি ধারণার প্রমাণটি করেছি, এবং প্রতিশ্রুতি হিসাবে, এটি সত্যিই দ্রুত কাজ করে, তবে আমি কেন EF ব্যবহার করছি তার একটি কারণ সম্পর্কিত তথ্যাদি সন্নিবেশ করানো সহজ, উদাহরণস্বরূপ যদি আমি ইতিমধ্যে সম্পর্কিত কোনও তথ্য সন্নিবেশ করানো হয় , এটি এটি sertোকানো হবে, আপনি কি কখনও এই দৃশ্যে প্রবেশ করেছেন? ধন্যবাদ!
বঙ্গো শার্প

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

2
আপনার কাঁচা গতির প্রয়োজন হয় বা আপনি যদি এই সন্নিবেশটি আবার চালাচ্ছেন তবে অবশ্যই স্কেলবুলকপিটি যাওয়ার উপায়। আমি এর আগে কয়েক মিলিয়ন রেকর্ড inোকিয়েছি এবং এটি অত্যন্ত দ্রুত। এটি বলেছে যে আপনি যদি এই সন্নিবেশটি পুনরায় চালানোর প্রয়োজন না হন তবে কেবল EF ব্যবহার করা সহজ হতে পারে।
নীল

49

আমি অ্যাডাম র্যাকিসের সাথে একমত SqlBulkCopyএকটি ডেটা উত্স থেকে অন্য ডেটাতে বাল্ক রেকর্ডার স্থানান্তরিত করার দ্রুততম উপায়। আমি এটি 20 কে রেকর্ড অনুলিপি করতে ব্যবহার করেছি এবং এটি 3 সেকেন্ডেরও কম সময় নিয়েছে। নীচের উদাহরণটি দেখুন।

public static void InsertIntoMembers(DataTable dataTable)
{           
    using (var connection = new SqlConnection(@"data source=;persist security info=True;user id=;password=;initial catalog=;MultipleActiveResultSets=True;App=EntityFramework"))
    {
        SqlTransaction transaction = null;
        connection.Open();
        try
        {
            transaction = connection.BeginTransaction();
            using (var sqlBulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, transaction))
            {
                sqlBulkCopy.DestinationTableName = "Members";
                sqlBulkCopy.ColumnMappings.Add("Firstname", "Firstname");
                sqlBulkCopy.ColumnMappings.Add("Lastname", "Lastname");
                sqlBulkCopy.ColumnMappings.Add("DOB", "DOB");
                sqlBulkCopy.ColumnMappings.Add("Gender", "Gender");
                sqlBulkCopy.ColumnMappings.Add("Email", "Email");

                sqlBulkCopy.ColumnMappings.Add("Address1", "Address1");
                sqlBulkCopy.ColumnMappings.Add("Address2", "Address2");
                sqlBulkCopy.ColumnMappings.Add("Address3", "Address3");
                sqlBulkCopy.ColumnMappings.Add("Address4", "Address4");
                sqlBulkCopy.ColumnMappings.Add("Postcode", "Postcode");

                sqlBulkCopy.ColumnMappings.Add("MobileNumber", "MobileNumber");
                sqlBulkCopy.ColumnMappings.Add("TelephoneNumber", "TelephoneNumber");

                sqlBulkCopy.ColumnMappings.Add("Deleted", "Deleted");

                sqlBulkCopy.WriteToServer(dataTable);
            }
            transaction.Commit();
        }
        catch (Exception)
        {
            transaction.Rollback();
        }

    }
}

1
আমি এই পোস্টে প্রদত্ত অনেকগুলি সমাধান চেষ্টা করেছিলাম এবং স্কেলবুলকপিটি ছিলো সবচেয়ে দ্রুত। খাঁটি ইএফ 15 মিনিট সময় নিয়েছিল, তবে সমাধানটির মিশ্রণ এবং স্কেলবুলকপি দিয়ে আমি 1.5 মিনিটে নামতে সক্ষম হয়েছি! এটি ছিল 2 মিলিয়ন রেকর্ডের সাথে! কোনও ডিবি সূচক অপ্টিমাইজেশন ছাড়াই।
jonas

তালিকাটি ডাটাবেলের চেয়ে সহজ than একটা ব্যাপার AsDataReader(): এক্সটেনশন পদ্ধতি, এই উত্তর ব্যাখ্যা stackoverflow.com/a/36817205/1507899
RJB

তবে এটি কেবল শীর্ষস্থানীয় ব্যক্তিত্বের জন্যই সম্পর্কিত নয়
জাহিদ মোস্তফা

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

23

EF ব্যবহার করে কীভাবে বাল্ক সন্নিবেশ করা যায় সে সম্পর্কে আমি এই নিবন্ধটি সুপারিশ করব।

সত্তা ফ্রেমওয়ার্ক এবং ধীর বাল্ক INSERTs

তিনি এই অঞ্চলগুলি ঘুরে দেখেন এবং পারফোল্যান্সের সাথে তুলনা করেন:

  1. ডিফল্ট ইএফ (30,000 রেকর্ড যুক্ত করা 57 মিনিট)
  2. ADO.NET কোড দিয়ে প্রতিস্থাপন করা হচ্ছে ( সেই একই 30,000 জনের 25 সেকেন্ড )
  3. প্রবন্ধ ব্লাট- কাজের প্রতিটি ইউনিটের জন্য একটি নতুন প্রসঙ্গ ব্যবহার করে সক্রিয় প্রবন্ধ গ্রাফকে ছোট রাখুন (একই 30,000 সন্নিবেশগুলি 33 সেকেন্ড সময় নেয়)
  4. বৃহত তালিকাগুলি - অটোডিটেক্ট চ্যাঞ্জগুলি সক্ষম করুন (সময়টি প্রায় 20 সেকেন্ডে নামিয়ে আনে)
  5. ব্যাচিং (১ 16 সেকেন্ডের নিচে)
  6. DbTable.AddRange () - (পারফরম্যান্স 12 সীমার মধ্যে রয়েছে)

21

যেহেতু এটি এখানে কখনই উল্লেখ করা হয়নি আমি এখানে ইএফসিওরকে পুনরায় ক্ষতিপূরণ দিতে চাই ul

context.BulkInsert(entitiesList);                 context.BulkInsertAsync(entitiesList);
context.BulkUpdate(entitiesList);                 context.BulkUpdateAsync(entitiesList);
context.BulkDelete(entitiesList);                 context.BulkDeleteAsync(entitiesList);
context.BulkInsertOrUpdate(entitiesList);         context.BulkInsertOrUpdateAsync(entitiesList);         // Upsert
context.BulkInsertOrUpdateOrDelete(entitiesList); context.BulkInsertOrUpdateOrDeleteAsync(entitiesList); // Sync
context.BulkRead(entitiesList);                   context.BulkReadAsync(entitiesList);

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

এইএফ 6.x
উপকারটি কি?

এটি যদি 10 টি সত্তার বেশি হয় তবে এটি অ্যাড্রেঞ্জ ব্যবহারের চেয়ে আরও বেশি পারফরম্যান্ট
জ্যাকাল

5
10 000 সন্নিবেশগুলি 9 মিনিট থেকে 12 সেকেন্ডে চলে গেছে। এটি আরও মনোযোগ প্রাপ্য!
কলিস্টো

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

18

আমি স্লুমার জবাবটি অনুসন্ধান করেছি (যা দুর্দান্ত, আইডিয়া ম্যানের জন্য ধন্যবাদ) এবং আমি সর্বোচ্চ গতি না আসা পর্যন্ত ব্যাচের আকার হ্রাস করেছি। স্লুমার ফলাফলগুলি দেখছি:

  • কমিটকাউন্ট = 1, পুনরুদ্ধারকন্টেক্সট = সত্য: 10 মিনিটেরও বেশি
  • কমিটকাউন্ট = 10, পুনরুদ্ধারকন্টেক্সট = সত্য: 241 সেকেন্ড
  • কমিটকাউন্ট = 100, রিরিকেট কনটেক্সট = সত্য: 164 সেকেন্ড
  • কমিটকাউন্ট = 1000, রিরিকেটকন্টেক্সট = সত্য: 191 সেকেন্ড

এটি দৃশ্যমান যে 1 থেকে 10 এবং 10 থেকে 100 থেকে সরানোর সময় গতি বৃদ্ধি রয়েছে, তবে 100 থেকে 1000 সন্নিবেশ করানোর গতি আবার কমছে।

সুতরাং আপনি যখন ব্যাচের আকার 10 এবং 100 এর মধ্যে কোথাও মানের জন্য হ্রাস করছেন তখন কী ঘটছে তার প্রতি আমি দৃষ্টি নিবদ্ধ রেখেছি এবং এখানে আমার ফলাফলগুলি রয়েছে (আমি বিভিন্ন সারির বিষয়বস্তু ব্যবহার করছি, তাই আমার সময়গুলি আলাদা মানের হয়):

Quantity    | Batch size    | Interval
1000    1   3
10000   1   34
100000  1   368

1000    5   1
10000   5   12
100000  5   133

1000    10  1
10000   10  11
100000  10  101

1000    20  1
10000   20  9
100000  20  92

1000    27  0
10000   27  9
100000  27  92

1000    30  0
10000   30  9
100000  30  92

1000    35  1
10000   35  9
100000  35  94

1000    50  1
10000   50  10
100000  50  106

1000    100 1
10000   100 14
100000  100 141

আমার ফলাফলের ভিত্তিতে, ব্যাচ আকারের জন্য প্রকৃত সর্বোত্তম মান প্রায় 30 এর কাছাকাছি। এটি 10 ​​এবং 100 উভয়েরই চেয়ে কম Pro সমস্যাটি হ'ল কেন 30 টি অনুকূল তা আমার কোনও ধারণা নেই এবং এর পক্ষে আমি কোনও যৌক্তিক ব্যাখ্যা খুঁজে পেতে পারি নি।


2
পোস্টগ্রাজ এবং খাঁটি এসকিউএল (এটি এসকিউএলের উপর নির্ভর করে ইএফ-তে নয়) এর সাথে 30 টি অনুকূল op
কামিল গারিভ

আমার অভিজ্ঞতা হ'ল বিভিন্ন সংযোগের গতি এবং সারি আকারের জন্য সর্বোত্তম পৃথক। দ্রুত সংযোগ এবং ছোট সারিগুলির জন্য সর্বোত্তম> 200 সারিও হতে পারে।
জিং

18

অন্য লোকেরা যেমন বলেছে যে আপনি যদি সত্যিই ভাল inোকানোর জন্য পারফরম্যান্স চান স্যাকলবুল্ককপি এটি করার উপায়।

এটি প্রয়োগ করা কিছুটা জটিল but তবে এমন লাইব্রেরি রয়েছে যা আপনাকে এটিতে সহায়তা করতে পারে। এখানে কয়েকটি রয়েছে তবে আমি নির্লজ্জভাবে এবার নিজের লাইব্রেরিটি প্লাগ করব: https://github.com/MikaelEliasson/EntityFramework.Utilities#batch-insert-entities

আপনার কেবলমাত্র কোডটির প্রয়োজন হবে:

 using (var db = new YourDbContext())
 {
     EFBatchOperation.For(db, db.BlogPosts).InsertAll(list);
 }

সুতরাং এটি কত দ্রুত? খুব বলতে কারণ এটি এখন সম্পূর্ণ অনেক কারণের, কম্পিউটার কর্মক্ষমতা, নেটওয়ার্ক, বস্তু আকার ইত্যাদি ইত্যাদি কর্মক্ষমতা পরীক্ষা আমি তৈরি করেছি যা প্রস্তাব 25k সত্ত্বা 10s কাছাকাছি সময়ে ঢোকানো যায় উপর নির্ভর করে হার্ড আদর্শ উপায় লোকালহোস্টের যদি আপনি আপনার EF কনফিগারেশনটি অনুকূল করেন অন্যান্য উত্তরে উল্লিখিত। EFUtilities সহ যা প্রায় 300 মিমি নিয়ে থাকে। আরও মজার বিষয় হ'ল আমি এই পদ্ধতিটি ব্যবহার করে 15 সেকেন্ডের নীচে প্রায় 3 মিলিয়ন সত্তা সংরক্ষণ করেছি, প্রতি সেকেন্ডে প্রায় 200k সত্তা গড়ে।

যদি আপনার রিলেটযুক্ত ডেটা toোকাতে প্রয়োজন হয় তবে একটি সমস্যা অবশ্যই হয়। উপরের পদ্ধতিটি ব্যবহার করে এটি দক্ষতার সাথে স্ক্যালি সার্ভারে করা যেতে পারে তবে এটির জন্য আপনার আইডি প্রজন্মের কৌশল থাকতে হবে যা আপনাকে পিতামাতার জন্য অ্যাপ-কোডে আইডি তৈরি করতে দেয় যাতে আপনি বিদেশী কীগুলি সেট করতে পারেন। এটি জিইউইডি বা হাইলো আইডি প্রজন্মের মতো কিছু ব্যবহার করে করা যেতে পারে।


ভাল কাজ করে. সিনট্যাক্সটি যদিও কিছুটা ভার্বোজ। আপনি মনে করেন EFBatchOperationযে DbContextপ্রতিটি স্ট্যাটিক পদ্ধতিতে পাস করার পরিবর্তে এমন কোনও কনস্ট্রাক্টর আপনি পাস করেন যা ভাল । জেনেরিক সংস্করণগুলি InsertAllএবং UpdateAllযা স্বয়ংক্রিয়ভাবে সংগ্রহটি সাদৃশ্য হিসাবে পাওয়া যায় তাও DbContext.Set<T>ভাল be
kjbartel

ধন্যবাদ বলার জন্য মাত্র একটি দ্রুত মন্তব্য! এই কোডটি আমাকে 1.5 সেকেন্ডে 170 কে রেকর্ড সংরক্ষণ করতে দেয়! আমি জল থেকে চেষ্টা করেছি এমন অন্য কোনও পদ্ধতি সম্পূর্ণরূপে ফুটিয়ে তোলে।
টম গ্লেন

@ মিকায়েল ওয়ান ইস্যুটি পরিচয় ক্ষেত্রগুলি নিয়ে কাজ করছে। আপনার পরিচয় সন্নিবেশ সক্রিয় করার উপায় আছে কি?
জো ফিলিপস 21

1
সত্তা ফ্রেমওয়ার্ক.বুল্কইনসার্টের বিপরীতে, এই গ্রন্থাগারটি ফ্রি ছিল। +1
রুডি

14

Dispose()প্রসঙ্গটি যদি সমস্যাগুলি তৈরি করে তবে সত্তা যদি আপনি Add()অন্যান্য পূর্ব লোড হওয়া সত্তাগুলির উপর নির্ভর করেন (যেমন: নেভিগেশন বৈশিষ্ট্য)

একই কর্মক্ষমতা অর্জন করতে আমি আমার প্রসঙ্গটি ছোট রাখতে একই ধারণা ব্যবহার করি

তবে Dispose()প্রসঙ্গের পরিবর্তে এবং পুনরায় তৈরি করার পরিবর্তে , আমি ইতিমধ্যে ইতিমধ্যে সত্ত্বাগুলি আলাদা করিSaveChanges()

public void AddAndSave<TEntity>(List<TEntity> entities) where TEntity : class {

const int CommitCount = 1000; //set your own best performance number here
int currentCount = 0;

while (currentCount < entities.Count())
{
    //make sure it don't commit more than the entities you have
    int commitCount = CommitCount;
    if ((entities.Count - currentCount) < commitCount)
        commitCount = entities.Count - currentCount;

    //e.g. Add entities [ i = 0 to 999, 1000 to 1999, ... , n to n+999... ] to conext
    for (int i = currentCount; i < (currentCount + commitCount); i++)        
        _context.Entry(entities[i]).State = System.Data.EntityState.Added;
        //same as calling _context.Set<TEntity>().Add(entities[i]);       

    //commit entities[n to n+999] to database
    _context.SaveChanges();

    //detach all entities in the context that committed to database
    //so it won't overload the context
    for (int i = currentCount; i < (currentCount + commitCount); i++)
        _context.Entry(entities[i]).State = System.Data.EntityState.Detached;

    currentCount += commitCount;
} }

এটিকে চেষ্টা করে ধরুন এবং আপনার TrasactionScope()যদি প্রয়োজন হয় তবে কোডটি পরিষ্কার রাখার জন্য এগুলি এখানে দেখানো হচ্ছে না


1
এটি সত্তা ফ্রেমওয়ার্ক .0.০ ব্যবহার করে সন্নিবেশ (অ্যাড্রেঞ্জ) কমিয়ে দেয়। 20.000 সারি সন্নিবেশ করা প্রায় 101 সেকেন্ড থেকে 118 সেকেন্ডে চলে গেছে।
এএইচ।

1
@ স্টেফেন হো: আমি আমার প্রসঙ্গটি নিষ্পত্তি এড়াতেও চেষ্টা করছি। আমি বুঝতে পারি এটি প্রসঙ্গটি পুনরুদ্ধার করার চেয়ে ধীর, তবে আমি জানতে চাই যে আপনি প্রসঙ্গটি পুনরুদ্ধার না করে বরং কমিটকাউন্টের সেট সহ এটি যথেষ্ট দ্রুত খুঁজে পেয়েছেন কিনা।
শিক্ষার্থী

@ লার্নার: আমি মনে করি প্রসঙ্গটি পুনরায় তৈরি করার চেয়ে এটি দ্রুত ছিল। তবে আমি এখন সত্যিই মনে করতে পারি না কারণ আমি শেষ পর্যন্ত স্কেলবুলকপি ব্যবহার করতে শুরু করেছিলাম।
স্টিফেন হো

আমি এই কৌশলটি ব্যবহার করে শেষ করেছি কারণ, কিছু অদ্ভুত কারণে, দ্বিতীয় পাসের সময় লুপটি পেরিয়ে ট্র্যাকিংয়ের কিছু বাকী ছিল, যদিও আমার কাছে সমস্ত কিছু ব্যবহারের বিবৃতিতে আবৃত ছিল এবং এমনকি ডিবি কনটেক্সটে ডিসপোজ () নামেও ডাকা হয়েছিল called । আমি যখন প্রসঙ্গে যুক্ত করব (২ য় পাসে) প্রসঙ্গ সেট সেট গণনাটি কেবল একটিটির পরিবর্তে 6 এ চলে যাবে। অন্য আইটেমগুলি যথেচ্ছভাবে যুক্ত হয়েছিল ইতিমধ্যে ওয়েল লুপটি দিয়ে প্রথম পাসে inোকানো হয়েছিল যাতে সেভচেনজেস-এ কলটি দ্বিতীয় পাসে ব্যর্থ হয়ে যায় (স্পষ্ট কারণে)।
হলমানাক

9

আমি জানি এটি একটি খুব পুরানো প্রশ্ন, তবে এখানকার এক ব্যক্তি বলেছেন যে EF এর সাথে বাল্ক সন্নিবেশ ব্যবহার করার জন্য একটি এক্সটেনশন পদ্ধতি তৈরি করেছে এবং আমি যখন যাচাই করেছিলাম তখন আবিষ্কার করেছি যে লাইব্রেরিটির দাম আজ one 599 (এক বিকাশকারীর জন্য)। পুরো লাইব্রেরির জন্য এটি বোধগম্য হতে পারে, তবে কেবলমাত্র বাল্ক সন্নিবেশ করার জন্য এটি অনেক বেশি।

এখানে আমি তৈরি একটি খুব সহজ এক্সটেনশন পদ্ধতি। আমি প্রথমে এটি ডেটাবেসের সাথে জোড়ায় ব্যবহার করি (কোডের সাথে প্রথমে পরীক্ষা করা হবে না, তবে আমি মনে করি এটি একই কাজ করে)। YourEntitiesআপনার প্রসঙ্গে নামের সাথে পরিবর্তন করুন :

public partial class YourEntities : DbContext
{
    public async Task BulkInsertAllAsync<T>(IEnumerable<T> entities)
    {
        using (var conn = new SqlConnection(Database.Connection.ConnectionString))
        {
            await conn.OpenAsync();

            Type t = typeof(T);

            var bulkCopy = new SqlBulkCopy(conn)
            {
                DestinationTableName = GetTableName(t)
            };

            var table = new DataTable();

            var properties = t.GetProperties().Where(p => p.PropertyType.IsValueType || p.PropertyType == typeof(string));

            foreach (var property in properties)
            {
                Type propertyType = property.PropertyType;
                if (propertyType.IsGenericType &&
                    propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    propertyType = Nullable.GetUnderlyingType(propertyType);
                }

                table.Columns.Add(new DataColumn(property.Name, propertyType));
            }

            foreach (var entity in entities)
            {
                table.Rows.Add(
                    properties.Select(property => property.GetValue(entity, null) ?? DBNull.Value).ToArray());
            }

            bulkCopy.BulkCopyTimeout = 0;
            await bulkCopy.WriteToServerAsync(table);
        }
    }

    public void BulkInsertAll<T>(IEnumerable<T> entities)
    {
        using (var conn = new SqlConnection(Database.Connection.ConnectionString))
        {
            conn.Open();

            Type t = typeof(T);

            var bulkCopy = new SqlBulkCopy(conn)
            {
                DestinationTableName = GetTableName(t)
            };

            var table = new DataTable();

            var properties = t.GetProperties().Where(p => p.PropertyType.IsValueType || p.PropertyType == typeof(string));

            foreach (var property in properties)
            {
                Type propertyType = property.PropertyType;
                if (propertyType.IsGenericType &&
                    propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    propertyType = Nullable.GetUnderlyingType(propertyType);
                }

                table.Columns.Add(new DataColumn(property.Name, propertyType));
            }

            foreach (var entity in entities)
            {
                table.Rows.Add(
                    properties.Select(property => property.GetValue(entity, null) ?? DBNull.Value).ToArray());
            }

            bulkCopy.BulkCopyTimeout = 0;
            bulkCopy.WriteToServer(table);
        }
    }

    public string GetTableName(Type type)
    {
        var metadata = ((IObjectContextAdapter)this).ObjectContext.MetadataWorkspace;
        var objectItemCollection = ((ObjectItemCollection)metadata.GetItemCollection(DataSpace.OSpace));

        var entityType = metadata
                .GetItems<EntityType>(DataSpace.OSpace)
                .Single(e => objectItemCollection.GetClrType(e) == type);

        var entitySet = metadata
            .GetItems<EntityContainer>(DataSpace.CSpace)
            .Single()
            .EntitySets
            .Single(s => s.ElementType.Name == entityType.Name);

        var mapping = metadata.GetItems<EntityContainerMapping>(DataSpace.CSSpace)
                .Single()
                .EntitySetMappings
                .Single(s => s.EntitySet == entitySet);

        var table = mapping
            .EntityTypeMappings.Single()
            .Fragments.Single()
            .StoreEntitySet;

        return (string)table.MetadataProperties["Table"].Value ?? table.Name;
    }
}

উত্তরাধিকার সূত্রে প্রাপ্ত যে কোনও সংগ্রহের বিরুদ্ধে আপনি এটি ব্যবহার করতে পারেন IEnumerable:

await context.BulkInsertAllAsync(items);

আপনার উদাহরণ কোডটি সম্পূর্ণ করুন। বাল্ককপিটি কোথায়
Seabizkit

1
এটি ইতিমধ্যে এখানে রয়েছে:await bulkCopy.WriteToServerAsync(table);
গিলহর্ম

সম্ভবত আমি পরিষ্কার ছিলাম না, আপনার লেখায় আপনি পরামর্শ দিয়েছিলেন যে আপনি একটি এক্সটেনশান করেছেন ... যার অর্থ আমি বোঝাতে চাইছি যে কোনও তৃতীয় অংশের lib এর প্রয়োজন নেই, যখন উভয় পদ্ধতিতেই SQLlulkCopy lib ব্যবহার করা হয়। এটি সম্পূর্ণরূপে SQLBulkCopy এর উপর নির্ভর করে, যখন আমি জিজ্ঞাসা করলাম বাল্ককপি কোথা থেকে আসে, এটি একটি এক্সটেনশন লিব যা আপনি উপরে একটি এক্সটেনশন লাইব লিখেছিলেন। এখানে আরও বলতে হবে যে আমি কীভাবে SQLBulkCopy lib ব্যবহার করেছি।
Seabizkit

সংযোগ সংস্করণ
রবার্ট

6

ব্যবহার করার চেষ্টা করুন সঞ্চিত পদ্ধতি যা আপনি প্রবেশ করতে চান এমন ডেটার একটি এক্সএমএল পাবেন।


9
আপনি যদি এক্সএমএল হিসাবে সংরক্ষণ করতে না চান তবে এক্সএমএল হিসাবে ডেটা পাস করার প্রয়োজন হয় না। এসকিউএল ২০০৮ এ আপনি টেবিলের মূল্যবান প্যারামিটার ব্যবহার করতে পারেন।
লাডিস্লাভ মির্নকা

আমি এটি স্পষ্ট করতে পারি নি তবে এসকিউএল 2005
বঙ্গো শার্প

4

আমি উপরে @ স্লুমার উদাহরণের জেনেরিক বর্ধন করেছি;

public static class DataExtensions
{
    public static DbContext AddToContext<T>(this DbContext context, object entity, int count, int commitCount, bool recreateContext, Func<DbContext> contextCreator)
    {
        context.Set(typeof(T)).Add((T)entity);

        if (count % commitCount == 0)
        {
            context.SaveChanges();
            if (recreateContext)
            {
                context.Dispose();
                context = contextCreator.Invoke();
                context.Configuration.AutoDetectChangesEnabled = false;
            }
        }
        return context;
    }
}

ব্যবহার:

public void AddEntities(List<YourEntity> entities)
{
    using (var transactionScope = new TransactionScope())
    {
        DbContext context = new YourContext();
        int count = 0;
        foreach (var entity in entities)
        {
            ++count;
            context = context.AddToContext<TenancyNote>(entity, count, 100, true,
                () => new YourContext());
        }
        context.SaveChanges();
        transactionScope.Complete();
    }
}

4

সত্তা ফ্রেমওয়ার্কে প্রবেশের দ্রুততম উপায়টি আমি সন্ধান করছি

বাল্ক সন্নিবেশকে সমর্থন করে এমন কয়েকটি তৃতীয় পক্ষের গ্রন্থাগার রয়েছে:

  • জেড.এন্টি ফ্রেমওয়ার্ক. এক্সটেনশনগুলি ( প্রস্তাবিত )
  • EFUtilities
  • EntityFramework.BulkInsert

দেখুন: সত্তা ফ্রেমওয়ার্ক বাল্ক সন্নিবেশ গ্রন্থাগার

সাবধান থাকুন, যখন একটি বাল্ক সন্নিবেশ গ্রন্থাগারটি চয়ন করেন। কেবল সত্ত্বা ফ্রেমওয়ার্ক এক্সটেনশানগুলি সকল ধরণের সমিতি এবং উত্তরাধিকারকে সমর্থন করে এবং এটি কেবলমাত্র সমর্থিত।


দাবি অস্বীকার : আমি এর মালিক সত্তা ফ্রেমওয়ার্ক এক্সটেনশনের

এই লাইব্রেরি আপনাকে আপনার পরিস্থিতিতে প্রয়োজনীয় সমস্ত বাল্ক ক্রিয়াকলাপ সম্পাদন করতে দেয়:

  • বাল্ক সেভ চেঞ্জস
  • বাল্ক সন্নিবেশ
  • বাল্ক মুছুন
  • বাল্ক আপডেট
  • বাল্ক মার্জ

উদাহরণ

// Easy to use
context.BulkSaveChanges();

// Easy to customize
context.BulkSaveChanges(bulk => bulk.BatchSize = 100);

// Perform Bulk Operations
context.BulkDelete(customers);
context.BulkInsert(customers);
context.BulkUpdate(customers);

// Customize Primary Key
context.BulkMerge(customers, operation => {
   operation.ColumnPrimaryKeyExpression = 
        customer => customer.Code;
});

19
এটি দুর্দান্ত এক্সটেনশন তবে বিনামূল্যে নয়
ওকান কোসিগিগিট

2
এই উত্তরটি বেশ ভাল এবং EntityFramework.BulkInsert 1.5 সেকেন্ডের মধ্যে 15K সারির একটি বাল্ক সন্নিবেশ সম্পাদন করে, উইন্ডোজ SERVICE এর মতো একটি অভ্যন্তরীণ প্রক্রিয়ার জন্য বেশ সুন্দর কাজ করে।
যাজক Cortes

4
হ্যাঁ, বাল্ক সন্নিবেশের জন্য 600।। মোটামুটি মূল্য।
ইক্রন

1
@ ইউক্রন ইয়েট এটির জন্য উপযুক্ত যদি আপনি এটি ব্যবহারিকভাবে ব্যবহার করেন। Something 600 নিয়ে আমি কোনও সমস্যা দেখতে পাচ্ছি না যে এটি নিজে তৈরি করতে আমাকে কয়েক ঘন্টা ব্যয় করতে হবে না যা আমার জন্য $ 600 এর থেকে অনেক বেশি ব্যয় করতে হবে। হ্যাঁ এটির জন্য অর্থ ব্যয় হয় তবে আমার প্রতি ঘন্টার হারের দিকে তাকানো এটি অর্থের ব্যয় ভাল!
জর্ডি ভ্যান আইজক

3

ব্যবহার SqlBulkCopy:

void BulkInsert(GpsReceiverTrack[] gpsReceiverTracks)
{
    if (gpsReceiverTracks == null)
    {
        throw new ArgumentNullException(nameof(gpsReceiverTracks));
    }

    DataTable dataTable = new DataTable("GpsReceiverTracks");
    dataTable.Columns.Add("ID", typeof(int));
    dataTable.Columns.Add("DownloadedTrackID", typeof(int));
    dataTable.Columns.Add("Time", typeof(TimeSpan));
    dataTable.Columns.Add("Latitude", typeof(double));
    dataTable.Columns.Add("Longitude", typeof(double));
    dataTable.Columns.Add("Altitude", typeof(double));

    for (int i = 0; i < gpsReceiverTracks.Length; i++)
    {
        dataTable.Rows.Add
        (
            new object[]
            {
                    gpsReceiverTracks[i].ID,
                    gpsReceiverTracks[i].DownloadedTrackID,
                    gpsReceiverTracks[i].Time,
                    gpsReceiverTracks[i].Latitude,
                    gpsReceiverTracks[i].Longitude,
                    gpsReceiverTracks[i].Altitude
            }
        );
    }

    string connectionString = (new TeamTrackerEntities()).Database.Connection.ConnectionString;
    using (var connection = new SqlConnection(connectionString))
    {
        connection.Open();
        using (var transaction = connection.BeginTransaction())
        {
            using (var sqlBulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, transaction))
            {
                sqlBulkCopy.DestinationTableName = dataTable.TableName;
                foreach (DataColumn column in dataTable.Columns)
                {
                    sqlBulkCopy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
                }

                sqlBulkCopy.WriteToServer(dataTable);
            }
            transaction.Commit();
        }
    }

    return;
}

3

একটি তালিকা সংরক্ষণের দ্রুততম উপায়গুলির মধ্যে আপনাকে নিম্নলিখিত কোডটি প্রয়োগ করতে হবে

context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;

AutoDetectChangesEn सक्षम = মিথ্যা

অ্যাডরেঞ্জ এবং সেভচেনজগুলি যুক্ত করুন: পরিবর্তনগুলি সনাক্ত করে না।

ValidateOnSaveEn اهل = মিথ্যা;

পরিবর্তন ট্র্যাকার সনাক্ত করে না

আপনাকে অবশ্যই নুগেট যুক্ত করতে হবে

Install-Package Z.EntityFramework.Extensions

এখন আপনি নিম্নলিখিত কোড ব্যবহার করতে পারেন

var context = new MyContext();

context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;

context.BulkInsert(list);
context.BulkSaveChanges();

আমি কি আপনার নমুনা কোডটি বাল্ক আপডেটের জন্য ব্যবহার করতে পারি?
আমিনগোলমাহলে

4
জেড লাইব্রেরিটি
নিখরচায়

3

স্কেলবুলকপিটি অতি দ্রুত quick

এটি আমার বাস্তবায়ন:

// at some point in my calling code, I will call:
var myDataTable = CreateMyDataTable();
myDataTable.Rows.Add(Guid.NewGuid,tableHeaderId,theName,theValue); // e.g. - need this call for each row to insert

var efConnectionString = ConfigurationManager.ConnectionStrings["MyWebConfigEfConnection"].ConnectionString;
var efConnectionStringBuilder = new EntityConnectionStringBuilder(efConnectionString);
var connectionString = efConnectionStringBuilder.ProviderConnectionString;
BulkInsert(connectionString, myDataTable);

private DataTable CreateMyDataTable()
{
    var myDataTable = new DataTable { TableName = "MyTable"};
// this table has an identity column - don't need to specify that
    myDataTable.Columns.Add("MyTableRecordGuid", typeof(Guid));
    myDataTable.Columns.Add("MyTableHeaderId", typeof(int));
    myDataTable.Columns.Add("ColumnName", typeof(string));
    myDataTable.Columns.Add("ColumnValue", typeof(string));
    return myDataTable;
}

private void BulkInsert(string connectionString, DataTable dataTable)
{
    using (var connection = new SqlConnection(connectionString))
    {
        connection.Open();
        SqlTransaction transaction = null;
        try
        {
            transaction = connection.BeginTransaction();

            using (var sqlBulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, transaction))
            {
                sqlBulkCopy.DestinationTableName = dataTable.TableName;
                foreach (DataColumn column in dataTable.Columns) {
                    sqlBulkCopy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
                }

                sqlBulkCopy.WriteToServer(dataTable);
            }
            transaction.Commit();
        }
        catch (Exception)
        {
            transaction?.Rollback();
            throw;
        }
    }
}

3

[2019 আপডেট] ইএফ কোর 3.1

উপরে যা বলা হয়েছে তা অনুসরণ করে, ইএফ কোর-এ অটোডিটেক্টট চেঞ্জস অক্ষম করা পুরোপুরি কাজ করেছিল: সন্নিবেশের সময়টি 100 দ্বারা বিভক্ত হয়েছিল (অনেক মিনিট থেকে কয়েক সেকেন্ড পর্যন্ত, ক্রস টেবিলের সম্পর্কযুক্ত 10 কে রেকর্ড)

আপডেট করা কোডটি হ'ল:

  context.ChangeTracker.AutoDetectChangesEnabled = false;
            foreach (IRecord record in records) {
               //Add records to your database        
            }
            context.ChangeTracker.DetectChanges();
            context.SaveChanges();
            context.ChangeTracker.AutoDetectChangesEnabled = true; //do not forget to re-enable

2

সত্তা ফ্রেমওয়ার্ক ব্যবহার এবং একটি বাস্তব বাস্তব উদাহরণে স্কেলবুল্ককপি ক্লাস ব্যবহারের মধ্যে পারফরম্যান্সের তুলনা এখানে করা হয়েছে: এসকিউএল সার্ভার ডাটাবেসে কমপ্লেক্স অবজেক্টগুলি কীভাবে সন্নিবেশ করা যায়

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


2

আরেকটি বিকল্প হ'ল নুগেট থেকে উপলভ্য স্কেলবুল্কটুলগুলি ব্যবহার করা। এটি ব্যবহার করা খুব সহজ এবং কিছু শক্তিশালী বৈশিষ্ট্য রয়েছে।

উদাহরণ:

var bulk = new BulkOperations();
var books = GetBooks();

using (TransactionScope trans = new TransactionScope())
{
    using (SqlConnection conn = new SqlConnection(ConfigurationManager
    .ConnectionStrings["SqlBulkToolsTest"].ConnectionString))
    {
        bulk.Setup<Book>()
            .ForCollection(books)
            .WithTable("Books") 
            .AddAllColumns()
            .BulkInsert()
            .Commit(conn);
    }

    trans.Complete();
}

আরও উদাহরণ এবং উন্নত ব্যবহারের জন্য ডকুমেন্টেশন দেখুন । দাবি অস্বীকার: আমি এই গ্রন্থাগারের লেখক এবং যে কোনও মতামত আমার নিজের মতামত।


2
এই প্রকল্পটি নুগেট এবং গিটহাব উভয় থেকে মুছে ফেলা হয়েছে।
0xced

1

আমার জ্ঞান অনুযায়ী সেখানে no BulkInsertআছেEntityFramework বিপুল টিপে কর্মক্ষমতা বৃদ্ধি করা সম্ভব।

এই পরিস্থিতিতে আপনি SqlBulkCopy এর ADO.netসাথে আপনার সমস্যা সমাধানের জন্য যেতে পারেন


আমি সেই ক্লাসটি একবার দেখেছিলাম, তবে এটি টেবিল টু-টেবিল সন্নিবেশকে আরও কেন্দ্রিক বলে মনে হচ্ছে, তাই না?
বঙ্গো শার্প

আপনি কী বলতে চাইছেন তা নিশ্চিত নন, এটিতে একটি ওভারলোডেড রয়েছে WriteToServerযা গ্রহণ করে DataTable
অন্ধরা

না। আপনি এসকিউএল থেকে নেট আটকান fromোকাতে পারবেন না hat আপনি কী খুঁজছেন?
anishMarokey

একটি ট্রানজেকশনস্কোপ ব্লকের মধ্যে ডাটাবেসে সম্ভাব্য কয়েক হাজার রেকর্ড সন্নিবেশ করার একটি উপায়
বঙ্গো শার্প

আপনি। নেট ট্রানজেকশনস্কোপ টেকনিকেট.মাইক্রোসফট /en-us/library/bb896149.aspx
anishMarokey

1

আপনি কি কখনও কোনও পটভূমি কর্মী বা কার্যের মাধ্যমে সন্নিবেশ করার চেষ্টা করেছেন?

আমার ক্ষেত্রে, 77 77 77০ টি নিবন্ধ সন্নিবেশ করানো হচ্ছে, বিদেশী কী সম্পর্কের (ন্যাভিগেশনপোপার্টি দ্বারা) 182 টি বিভিন্ন টেবিলে বিতরণ করা হয়েছে।

কাজটি ছাড়াই, এটি সময় নেয় 2 মিনিট এবং অর্ধেক। একটি কার্যের মধ্যে (Task.Factory.StartNew(...) ) এর মধ্যে, এটি 15 সেকেন্ড সময় নিয়েছিল।

আমি SaveChanges()সমস্ত সত্ত্বাকে প্রসঙ্গে যুক্ত করার পরে কেবল এটি করছি। (ডেটা অখণ্ডতা নিশ্চিত করতে)


2
আমি নিশ্চিত যে প্রসঙ্গটি থ্রেড নিরাপদ নয়। সমস্ত সত্তা সংরক্ষিত হয়েছে তা নিশ্চিত করার জন্য আপনার কি পরীক্ষা আছে?
ড্যানি ভারোদ

আমি জানি যে পুরো সত্তা কাঠামোটি থ্রেডটি মোটেই নিরাপদ নয়, তবে আমি কেবলমাত্র প্রসঙ্গগুলিতে অবজেক্টগুলি যুক্ত করছি এবং শেষে সংরক্ষণ করছি ... এটি এখানে পুরোপুরি কার্যকর।
রাফেল এএমএস

সুতরাং, আপনি DbContext.SaveChanges () কে মূল থ্রেডে কল দিচ্ছেন, তবে প্রসঙ্গের সাথে সত্তা যুক্ত করা ব্যাকগ্রাউন্ড থ্রেডে সঞ্চালিত হবে, তাই না?
প্রোকুরার্স

1
হ্যাঁ, থ্রেডগুলির মধ্যে ডেটা যুক্ত করুন; সব শেষ হওয়ার জন্য অপেক্ষা করুন; এবং মূল থ্রেড পরিবর্তনগুলি সংরক্ষণ করুন
রাফায়েল এএমএস

যদিও আমি মনে করি যে এই উপায়টি বিপজ্জনক এবং ভুলগুলির প্রবণ, তবে আমি এটি খুব আকর্ষণীয় বলে মনে করি।
শিক্ষার্থী

1

এখানে লিখিত সমস্ত সমাধানগুলি সহায়তা করে না কারণ আপনি যখন SaveChanges () করেন, সন্নিবেশের বিবৃতিগুলি ডাটাবেসে একের পর এক প্রেরণ করা হয়, সত্তা এভাবেই কাজ করে।

এবং উদাহরণস্বরূপ আপনার ডাটাবেস এবং পিছনে ভ্রমণ যদি 50 এমএস হয় তবে সন্নিবেশের জন্য প্রয়োজনীয় সময়টি রেকর্ডের সংখ্যা x 50 এমএস।

আপনাকে বাল্কইনসার্ট ব্যবহার করতে হবে, এখানে লিঙ্কটি দেওয়া হয়েছে: https://efulkinsert.codeplex.com/

আমি প্রবেশের সময়টি এটি ব্যবহার করে 5-6 মিনিট থেকে 10-12 সেকেন্ডে হ্রাস পেয়েছি।


1

আপনি বাল্ক প্যাকেজ লাইব্রেরি ব্যবহার করতে পারেন । সত্ত্বা কাঠামো> = 6.0.0 থাকা প্রকল্পগুলিতে বাল্ক সন্নিবেশ 1.0.0 সংস্করণ ব্যবহৃত হয়।

আরও বিবরণ এখানে পাওয়া যাবে- বাল্কোপরেশন উত্স কোড


1

[পোষ্টগ্রিসকিউএলএর জন্য নতুন সমাধান] আরে, আমি জানি এটি বেশ পুরানো পোস্ট, তবে আমি সম্প্রতি একই ধরণের সমস্যায় পড়েছি, তবে আমরা পোস্টগ্র্যাসকিএল ব্যবহার করছিলাম were আমি কার্যকর বালকিনেট ব্যবহার করতে চেয়েছিলাম, যা খুব কঠিন হয়ে উঠল। এই ডিবিতে এটি করার জন্য আমি কোনও উপযুক্ত নিখরচায় গ্রন্থাগার পাইনি। আমি কেবল এই সহায়কটি পেয়েছি: https://bytefish.de/blog/postgresql_bulk_insert/ যা নুগেটেও রয়েছে। আমি একটি ছোট ম্যাপার লিখেছি, যা সত্তা ফ্রেমওয়ার্ককে অটো ম্যাপ করে দেয়:

public static PostgreSQLCopyHelper<T> CreateHelper<T>(string schemaName, string tableName)
        {
            var helper = new PostgreSQLCopyHelper<T>("dbo", "\"" + tableName + "\"");
            var properties = typeof(T).GetProperties();
            foreach(var prop in properties)
            {
                var type = prop.PropertyType;
                if (Attribute.IsDefined(prop, typeof(KeyAttribute)) || Attribute.IsDefined(prop, typeof(ForeignKeyAttribute)))
                    continue;
                switch (type)
                {
                    case Type intType when intType == typeof(int) || intType == typeof(int?):
                        {
                            helper = helper.MapInteger("\"" + prop.Name + "\"",  x => (int?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
                            break;
                        }
                    case Type stringType when stringType == typeof(string):
                        {
                            helper = helper.MapText("\"" + prop.Name + "\"", x => (string)typeof(T).GetProperty(prop.Name).GetValue(x, null));
                            break;
                        }
                    case Type dateType when dateType == typeof(DateTime) || dateType == typeof(DateTime?):
                        {
                            helper = helper.MapTimeStamp("\"" + prop.Name + "\"", x => (DateTime?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
                            break;
                        }
                    case Type decimalType when decimalType == typeof(decimal) || decimalType == typeof(decimal?):
                        {
                            helper = helper.MapMoney("\"" + prop.Name + "\"", x => (decimal?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
                            break;
                        }
                    case Type doubleType when doubleType == typeof(double) || doubleType == typeof(double?):
                        {
                            helper = helper.MapDouble("\"" + prop.Name + "\"", x => (double?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
                            break;
                        }
                    case Type floatType when floatType == typeof(float) || floatType == typeof(float?):
                        {
                            helper = helper.MapReal("\"" + prop.Name + "\"", x => (float?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
                            break;
                        }
                    case Type guidType when guidType == typeof(Guid):
                        {
                            helper = helper.MapUUID("\"" + prop.Name + "\"", x => (Guid)typeof(T).GetProperty(prop.Name).GetValue(x, null));
                            break;
                        }
                }
            }
            return helper;
        }

আমি এটি নিম্নলিখিত উপায়ে ব্যবহার করি (আন্ডারটেকিং নামে আমার সত্তা ছিল):

var undertakingHelper = BulkMapper.CreateHelper<Model.Undertaking>("dbo", nameof(Model.Undertaking));
undertakingHelper.SaveAll(transaction.UnderlyingTransaction.Connection as Npgsql.NpgsqlConnection, undertakingsToAdd));

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

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


0

গোপন হ'ল একটি অভিন্ন ফাঁকা মঞ্চ টেবিল .োকানো। সন্নিবেশগুলি দ্রুত হালকা করা হচ্ছে। তারপরে এটি থেকে আপনার প্রধান বৃহত টেবিলটিতে একটি সন্নিবেশ চালান । তারপরে পরবর্তী ব্যাচের জন্য প্রস্তুত স্টেজিং টেবিলটি কেটে ফেলুন।

অর্থাত।

insert into some_staging_table using Entity Framework.

-- Single insert into main table (this could be a tiny stored proc call)
insert into some_main_already_large_table (columns...)
   select (columns...) from some_staging_table
truncate table some_staging_table

EF ব্যবহার করে, আপনার সমস্ত রেকর্ড খালি মঞ্চের টেবিলে যুক্ত করুন। তারপরে একটি একক এসকিউএল নির্দেশে মূল (বৃহত এবং ধীর) সারণিতে সন্নিবেশ করতে এসকিউএল ব্যবহার করুন । তারপরে আপনার মঞ্চের টেবিলটি খালি করুন। এটি ইতিমধ্যে একটি বড় টেবিলের মধ্যে প্রচুর ডেটা ofোকানোর একটি খুব দ্রুত উপায়।
সাইমন হিউজেস

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

-1

তবে, (+4000) এর বেশি সন্নিবেশের জন্য আমি সঞ্চিত প্রক্রিয়াটি ব্যবহার করার পরামর্শ দিই। সময় অতিবাহিত সংযুক্ত। আমি এটি "" এ 11.788 সারি প্রবেশ করিয়েছিএখানে চিত্র বর্ণনা লিখুন

এটি কোড thats

 public void InsertDataBase(MyEntity entity)
    {
        repository.Database.ExecuteSqlCommand("sp_mystored " +
                "@param1, @param2"
                 new SqlParameter("@param1", entity.property1),
                 new SqlParameter("@param2", entity.property2));
    }

-1

সঞ্চিত পদ্ধতি ব্যবহার করুন যা ডেটা toোকাতে এক্সএমএল আকারে ইনপুট ডেটা নেয়।

আপনার সি # কোড থেকে এক্সএমএল হিসাবে প্রবেশের তথ্য প্রবেশ করুন।

যেমন সি # তে সিনট্যাক্সটি এরকম হবে:

object id_application = db.ExecuteScalar("procSaveApplication", xml)

-7

সত্তা ফ্রেমওয়ার্কে রেকর্ড সন্নিবেশ করার গতি বাড়াতে এই কৌশলটি ব্যবহার করুন। এখানে আমি রেকর্ডগুলি সন্নিবেশ করতে একটি সাধারণ সঞ্চিত পদ্ধতি ব্যবহার করি। এবং এই সঞ্চিত পদ্ধতিটি কার্যকর করতে আমি ব্যবহার করি .FromSql () সত্তা ফ্রেমওয়ার্কের পদ্ধতি যা কাঁচা এসকিউএল চালায়।

সঞ্চিত পদ্ধতি কোড:

CREATE PROCEDURE TestProc
@FirstParam VARCHAR(50),
@SecondParam VARCHAR(50)

AS
  Insert into SomeTable(Name, Address) values(@FirstParam, @SecondParam) 
GO

এরপরে, আপনার সমস্ত 4000 রেকর্ডের মধ্য দিয়ে লুপ করুন এবং সঞ্চিত কার্যকর করে এমন সত্ত্বা ফ্রেমওয়ার্ক কোড যুক্ত করুন

পদ্ধতি প্রতি 100 ম লুপ onces।

এর জন্য আমি এই পদ্ধতিটি কার্যকর করতে একটি স্ট্রিং ক্যোয়ারী তৈরি করি, এটিতে প্রতিটি রেকর্ডের সেট যুক্ত করে রাখুন।

তারপরে এটি পরীক্ষা করে নিন যে লুপটি 100 এর গুণকগুলিতে চলছে এবং সে ক্ষেত্রে এটি ব্যবহার করে কার্যকর করুন .FromSql()

সুতরাং 4000 রেকর্ডের জন্য আমাকে কেবল 4000/100 = 40 বারের জন্য প্রক্রিয়া চালাতে হবে ।

নীচের কোডটি পরীক্ষা করুন:

string execQuery = "";
var context = new MyContext();
for (int i = 0; i < 4000; i++)
{
    execQuery += "EXEC TestProc @FirstParam = 'First'" + i + "'', @SecondParam = 'Second'" + i + "''";

    if (i % 100 == 0)
    {
        context.Student.FromSql(execQuery);
        execQuery = "";
    }
}

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