2012-11-20 9 views
5

में अपग्रेड करने के बाद प्रदर्शन में गिरावट आई। मेरे पास .NET 4.0 एप्लिकेशन में एक ईएफ 4 मॉडल था जिसे मैं .NET 4.5 और EF5 में अपग्रेड करता हूं (नई इकाई फ़्रेमवर्क 5 असेंबली का संदर्भ देता हूं), मैंने "कोड जनरेशन" रणनीति "से" कोई नहीं "और मॉडल में कोड जनरेशन आइटम (ईएफ 5.x डीबीकॉन्टेक्स्ट जेनरेटर) जोड़ा। जो लगभग किसी भी स्थिति में ठीक काम करता है। लेकिन अब जब मैं नेविगेशन प्रॉपर्टी एक्सेस करता हूं तो बहुत बड़ी समस्याएं होती हैं जो बहुत सारे रिकॉर्ड (> 100,000 रिकॉर्ड्स) का संदर्भ देती है। डेटाबेस एक एमएसएसएलएल 2005 सर्वर है।EF4 मॉडल को EF5 मॉडल (डीबीकॉन्टेक्स्ट)

मेरे परिदृश्य इस तरह दिखता है:

मेरी DB में हर ग्राहक एक अद्वितीय ID (यह DB में प्राथमिक कुंजी है), इसके अलावा में हर ग्राहक रिकॉर्ड एक माता पिता के ग्राहक आईडी (इस विशेष मामले में लगभग हर शामिल है एक ही मूल आईडी के ग्राहक संदर्भ (150,000 रिकॉर्ड से लगभग 145,000 रिकॉर्ड) जो आईडी 1 के साथ रिकॉर्ड है)।

मेरे मॉडल में DbSet<CustomerBase> CustomerBase है जो तालिका का प्रतिनिधित्व करता है जिसमें सभी ग्राहकों को अपना डेटा शामिल होता है। इसके अलावा ICollection<CustomerBase> CustomerBaseChildren और ICollection<CustomerBase> CustomerBaseParent नामक नेविगेशन गुण हैं जो ग्राहक आईडी और ग्राहक मूल आईडी को 0..1 से * बहुतायत से कनेक्ट करते हैं।

मैं एक सरलीकृत संस्करण का निर्माण प्रदर्शित करने के लिए मैं क्या मतलब है:

इस परीक्षण के लिए 150.000 रिकॉर्ड के साथ तालिका बिल्ड:

CREATE TABLE CustomerBase 
(
    id int IDENTITY(1,1) PRIMARY KEY NOT NULL, 
    parent_id int FOREIGN KEY REFERENCES CustomerBase(id), 
    some_data1 varchar(100), 
    some_data2 varchar(100), 
    some_data3 varchar(100), 
    some_data4 varchar(100), 
    some_data5 varchar(100), 
) 
GO 

DECLARE @i int = 0 
WHILE @i < 150000 BEGIN 
    INSERT INTO CustomerBase (parent_id, some_data1, some_data2, some_data3, some_data4, some_data5) VALUES (1, newid(), newid(), newid(), newid(), newid()) 

    SET @i = @i + 1 
END 

आयात एक नई इकाई मॉडल में referencial बाधा सहित तालिका। मैंने "इकाई कंटेनर नाम" ef5Entities के रूप में उपयोग किया। फिर मैंने नेविगेशन प्रोपर्टीज ग्राहकबेस 1 और कस्टमरबेस 2 को ग्राहकबेस चेल्डर और ग्राहकबेस पेरेंट में बदल दिया।

static void Main(string[] args) 
{ 
    ef5Entities context = new ef5Entities(); 

    // Start with selecting a single customer. 
    // Works fine in EF4/ObjectContext, works even faster in in EF5/DbContext 
    CustomerBase someCustomer = context.CustomerBase.First(customer => customer.id == 1234); 
    // Do something ... 

    // Get the parent of the customer. 
    // Works fine in EF4/ObjectContext, works even faster in in EF5/DbContext 
    CustomerBase parentCustomer = someCustomer.CustomerBaseParent; 
    // Do something ... 

    // Get the first child of the given parent id. 
    // Takes about 10 seconds in EF4/ObjectContext, I stopped the debugger after 2 minutes waiting in EF5/DbContext 
    CustomerBase firstChild = parentCustomer.CustomerBaseChildren.First(); 

    Console.WriteLine("Press any key to quit."); 
    Console.ReadKey(); 
} 

मैं एसक्यूएल सर्वर प्रोफाइलर इस्तेमाल किया क्या इकाई की रूपरेखा डेटाबेस पर निष्पादित देखने के लिए:

और यहाँ मेरे नमूना अनुप्रयोग है। ऐसा लगता है कि EF4 और EF5 कोड बिल्कुल वैसा ही है:

SELECT TOP (1) 
[Extent1].[id] AS [id], 
[Extent1].[parent_id] AS [parent_id], 
[Extent1].[some_data1] AS [some_data1], 
[Extent1].[some_data2] AS [some_data2], 
[Extent1].[some_data3] AS [some_data3], 
[Extent1].[some_data4] AS [some_data4], 
[Extent1].[some_data5] AS [some_data5] 
FROM [dbo].[CustomerBase] AS [Extent1] 
WHERE 1234 = [Extent1].[id] 

exec sp_executesql N'SELECT 
[Extent1].[id] AS [id], 
[Extent1].[parent_id] AS [parent_id], 
[Extent1].[some_data1] AS [some_data1], 
[Extent1].[some_data2] AS [some_data2], 
[Extent1].[some_data3] AS [some_data3], 
[Extent1].[some_data4] AS [some_data4], 
[Extent1].[some_data5] AS [some_data5] 
FROM [dbo].[CustomerBase] AS [Extent1] 
WHERE [Extent1].[id] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1 

exec sp_executesql N'SELECT 
[Extent1].[id] AS [id], 
[Extent1].[parent_id] AS [parent_id], 
[Extent1].[some_data1] AS [some_data1], 
[Extent1].[some_data2] AS [some_data2], 
[Extent1].[some_data3] AS [some_data3], 
[Extent1].[some_data4] AS [some_data4], 
[Extent1].[some_data5] AS [some_data5] 
FROM [dbo].[CustomerBase] AS [Extent1] 
WHERE [Extent1].[parent_id] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1 

अगर मैं एसक्यूएल प्रबंधन स्टूडियो में सभी तीन स्टेटमेंट्स को निष्पादित, यह जब तक सभी 1 + 1 + 150.000 रिकॉर्ड लाई जाती हैं, लगभग 1-2 सेकंड लेता है।

लेकिन जैसा कि मैं समझता हूं कि तीसरा कथन समस्या है। यह 150,000 रिकॉर्ड लौटाता है (भले ही मैं ऊपर दिए गए कोड या .Single() या .Take(10) पर .First() का उपयोग करता हूं, भले ही मैं इसके सामने .OrderBy(...) का उपयोग करता हूं या नहीं। ऐसा लगता है कि एंटीटी फ्रेमवर्क सभी 150,000 रिकॉर्ड्स लाता है और डीबीकॉन्टेक्स्ट में रिकॉर्ड कैश करने में एक भयानक लगता है बहुत समय (2 मिनट प्रतीक्षा करने के बाद मैंने परीक्षण कोड को रोक दिया, इसे अपने वास्तविक ग्राहक आधार तालिका के साथ परीक्षण करने में 100 मिनट लग गए)। ऑब्जेक्ट कॉन्टेक्स्ट में कैशिंग केवल 10 सेकंड लेता है (यह मानना ​​बुरा है कि डेटाबेस स्वयं 5 है -10 गुना तेजी से, लेकिन मैं उस के साथ जीवन सकता है)।

यहां तक ​​कि स्मृति की खपत, बुरी है ObjectContext साथ आवेदन कार्य सेट 200MB के बारे में उठता है, DbContext साथ कार्य सेट के बारे में 10 गुना अधिक उठाती है।

क्या डेटाबेस से सभी रिकॉर्ड प्राप्त करना बंद करने के लिए चुनिंदा कथन में एक शीर्ष (एन) खंड इंजेक्ट करने का कोई तरीका है यदि मैं केवल पहला रिकॉर्ड या पहला एन रिकॉर्ड (सामान्य 10 से 100 रिकॉर्ड) चाहता हूं? पहले वक्तव्य में चयन विवरण (या एक शीर्ष (2) में एक शीर्ष (1) था यदि .First() के बजाय .Single() का उपयोग करें)।

मैं भी कोई ट्रैकिंग के लिए लाइन CustomerBase someCustomer = context.CustomerBase.First(customer => customer.id == 1234); बदलने की कोशिश की: CustomerBase someCustomer = context.CustomerBase.AsNoTracking().First(customer => customer.id == 1234);

लेकिन फिर एक निम्न संदेश के साथ CustomerBase firstChild = parentCustomer.CustomerBaseChildren.First(); में एक System.InvalidOperationException मिलती है:

जब एक वस्तु एक NoTracking मर्ज विकल्प के साथ दिया जाता है, लोड केवल तभी कहा जा सकता है जब EntityCollection या EntityReference में ऑब्जेक्ट्स नहीं होते हैं।

यदि मैं कोड जनरेशन रणनीति को EF5 के साथ ऑब्जेक्ट कॉन्टेक्स्ट का उपयोग करने के लिए वापस बदलता हूं तो सब कुछ पुराने पुराने ईएफ 4 की तरह ठीक काम करता है। क्या मैं डीबीकॉन्टेक्स्ट का उपयोग करते समय कुछ गलत कर रहा हूं या डीबीकॉन्टेक्स्ट बड़े वातावरण में उपयोग करने योग्य नहीं है?

उत्तर

1

मैंने हाल ही में विजुअल स्टूडियो 2013, .NET 4.5.1 और इकाई फ्रेमवर्क 6 में अपग्रेड किया है। यदि मैं अपने मॉडल को ईएफ 5 के बजाय ईएफ 6 का उपयोग करने के लिए संशोधित करता हूं तो यह एक आकर्षण की तरह काम करता है।

तो समाधान EF4/EF5 का उपयोग ऑब्जेक्ट कॉन्टेक्स्ट या EF6 के साथ DbContext के साथ करना है।

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^