सी # एंटिटी फ्रेमवर्क: बल्क एक्सटेंशन्स इनपुट मेमोरी इश्यू
मैं वर्तमान में EF एक्सटेंशन का उपयोग कर रहा हूं। एक बात मुझे समझ में नहीं आती, "इसके प्रदर्शन में मदद करना चाहिए"
हालाँकि सूची चर में एक मिलियन + रिकॉर्ड रखना, एक मेमोरी इश्यू है। तो अगर स्मृति में सब कुछ पकड़े बिना, मिलियन रिकॉर्ड अपडेट करना चाहते हैं, तो यह कैसे कुशलतापूर्वक किया जा सकता है?
क्या हमें for loop
10,000 का कहना है कि बैचों में अद्यतन करना चाहिए ? क्या EFExtensions BulkUpdate के पास इसकी समर्थन करने के लिए कोई मूल कार्यक्षमता है?
उदाहरण:
var productUpdate = _dbContext.Set<Product>()
.Where(x => x.ProductType == 'Electronics'); // this creates IQueryable
await productUpdate.ForEachAsync(c => c.ProductBrand = 'ABC Company');
_dbContext.BulkUpdateAsync(productUpdate.ToList());
संसाधन:
https://entityframework-extensions.net/bulk-update
जवाब
मुझे "उचित" EF एक्सटेंशन का तरीका एक क्वेरी-जैसी स्थिति के साथ बल्क अपडेट करने के लिए मिला:
var productUpdate = _dbContext.Set<Product>()
.Where(x => x.ProductType == 'Electronics')
.UpdateFromQuery( x => new Product { ProductBrand = "ABC Company" });
दस्तावेज़ीकरण केUPDATE ... SET ... WHERE
अनुसार, पहले संस्थाओं को लोड करने की आवश्यकता के बिना उचित SQL में परिणाम होना चाहिए :
क्यों
UpdateFromQuery
तेजी से हैSaveChanges
,BulkSaveChanges
औरBulkUpdate
?
UpdateFromQuery
SQL में सीधे एक स्टेटमेंट को निष्पादित करता है जैसे किUPDATE [TableName] SET [SetColumnsAndValues] WHERE [Key]
।अन्य ऑपरेशनों में सामान्य रूप से एक या कई डेटाबेस राउंड-ट्रिप की आवश्यकता होती है जो प्रदर्शन को धीमा कर देती है।
आप उनके उदाहरण से अनुकूलित इस डॉटनेट फिडेल उदाहरण पर कार्य सिंटैक्स की जांच कर सकते हैं BulkUpdate
।
अन्य बातें
दुर्भाग्य से, इसके लिए बैच संचालन का कोई उल्लेख नहीं है।
इस तरह से एक बड़ा अपडेट करने से पहले, इस कॉलम पर आपके द्वारा बनाए गए अनुक्रमणिका को निष्क्रिय करने पर विचार करने के लायक हो सकता है, और बाद में उनका पुनर्निर्माण कर सकता है। यदि आप उनमें से कई हैं तो यह विशेष रूप से उपयोगी है।
में स्थिति के बारे में सावधान
Where
, यदि इसे EF द्वारा SQL के रूप में अनुवादित नहीं किया जा सकता है, तो इसे क्लाइंट साइड किया जाएगा, जिसका अर्थ है "सामान्य" भयानक राउंडट्रिप "लोड - मेमोरी में बदलाव - अपडेट"
यह वास्तव में कुछ ऐसा है जिसे ईएफ के लिए नहीं बनाया गया है। ईएफ का डेटाबेस इंटरैक्शन रिकॉर्ड ऑब्जेक्ट से शुरू होता है, और वहां से प्रवाह होता है। यदि इकाई को ट्रैक नहीं किया गया (और इसलिए लोड किया गया) नहीं बदला गया है, तो EF एक आंशिक अद्यतन (यानी सब कुछ अधिलेखित नहीं) उत्पन्न नहीं कर सकता है, और इसी तरह यह कुंजी के बजाय एक शर्त के आधार पर रिकॉर्ड रिकॉर्ड नहीं कर सकता है।
सशर्त अद्यतन के लिए कोई ईएफ समतुल्य (उन सभी अभिलेखों को लोड किए बिना) नहीं है जैसे तर्क को हटा दें
UPDATE People
SET FirstName = 'Bob'
WHERE FirstName = 'Robert'
या
DELETE FROM People
WHERE FirstName = 'Robert'
ईएफ दृष्टिकोण का उपयोग करके ऐसा करने से आपको इन सभी संस्थाओं को डेटाबेस में वापस भेजने के लिए लोड करना होगा (अपडेट या डिलीट के साथ), और यह बैंडविड्थ और प्रदर्शन की बर्बादी है जैसा कि आप पहले ही पा चुके हैं।
सबसे अच्छा समाधान जो मैंने यहां पाया है, वह ईएफ के लिनक्यू-अनुकूल तरीकों को बायपास करने के बजाय कच्चे एसक्यूएल को स्वयं निष्पादित करना है। यह अभी भी एक ईएफ संदर्भ का उपयोग करके किया जा सकता है।
using (var ctx = new MyContext())
{
string updateCommand = "UPDATE People SET FirstName = 'Bob' WHERE FirstName = 'Robert'";
int noOfRowsUpdated = ctx.Database.ExecuteSqlCommand(updateCommand);
string deleteCommand = "DELETE FROM People WHERE FirstName = 'Robert'";
int noOfRowsDeleted = ctx.Database.ExecuteSqlCommand(deleteCommand);
}
अधिक जानकारी यहाँ । बेशक एसक्यूएल इंजेक्शन से बचाना न भूलें जहाँ प्रासंगिक हो।
कच्चे SQL को चलाने के लिए विशिष्ट वाक्यविन्यास EF / EF कोर के प्रति संस्करण में भिन्न हो सकता है लेकिन जहाँ तक मुझे पता है सभी संस्करण आपको कच्चे SQL को निष्पादित करने की अनुमति देते हैं।
मैं विशेष रूप से EF एक्सटेंशन या BulkUpdate के प्रदर्शन पर टिप्पणी नहीं कर सकता, और मैं उनसे इसे खरीदने नहीं जा रहा हूं।
उनके प्रलेखन के आधार पर, उन्हें सशर्त अद्यतन / तर्क को हटाने की अनुमति देने के लिए सही हस्ताक्षर वाले तरीके नहीं लगते हैं।
BulkUpdate
ऐसा लगता नहीं है कि आप तार्किक स्थिति (अपने अद्यतन आदेश में WHERE) को इनपुट करने की अनुमति देते हैं जो आपको इसे अनुकूलित करने की अनुमति देगा।BulkDelete
अभी भी एकBatchSize
सेटिंग है, जो बताती है कि वे अभी भी रिकॉर्ड्स को एक बार (अच्छी तरह से, प्रति बैच मुझे लगता है) को संभाल रहे हैं, और एक शर्त के साथ एक भी DELETE क्वेरी का उपयोग नहीं कर रहे हैं (WHERE क्लॉज)।
प्रश्न में आपके इच्छित कोड के आधार पर, EF एक्सटेंशन वास्तव में आपको वह नहीं दे रहा है जिसकी आपको आवश्यकता है। यह डेटाबेस पर कच्चे एसक्यूएल को निष्पादित करने के लिए अधिक प्रदर्शन और सस्ता है, क्योंकि यह ईएफ को अपनी संस्थाओं को लोड करने की आवश्यकता को दरकिनार करता है।
अद्यतन
मैं सही हो सकता है, सशर्त अद्यतन तर्क के लिए कुछ समर्थन है, जैसा कि यहां देखा गया है । हालाँकि, यह मेरे लिए स्पष्ट नहीं है, जबकि उदाहरण अभी भी स्मृति में सब कुछ लोड करता है और फिर उस सशर्त का उद्देश्य क्या है, जहां यदि आपने पहले ही इसे सभी मेमोरी में लोड किया है (तो इन-मेमोरी लिनेक्यू का उपयोग क्यों नहीं करते हैं?)
हालाँकि, भले ही यह संस्थाओं को लोड किए बिना काम करता हो, फिर भी यह है:
- SQL की तुलना में अधिक सीमित (केवल समानता जांच की अनुमति दी जाती है, जो किसी भी बूलियन स्थिति की अनुमति देता है जो मान्य SQL है)
- अपेक्षाकृत जटिल (मुझे उनका वाक्यविन्यास पसंद नहीं है, शायद यह व्यक्तिपरक है)
- और अधिक महंगा (अभी भी एक भुगतान पुस्तकालय)
अपनी खुद की कच्ची SQL क्वेरी को रोल करने की तुलना में। मैं अभी भी अपने कच्चे एसक्यूएल को यहाँ रोल करने का सुझाव दूंगा, लेकिन यह सिर्फ मेरी राय है।