2011-03-16 12 views
13

यह प्रश्न माइक्रोसॉफ्ट एंटिटी फ्रेमवर्क का उपयोग करके कई आवेषण या अपडेट को संभालने के लिए सर्वोत्तम अभ्यास के संबंध में है। समस्या यह है कि हमने एक लंबे समय से चलने वाला कार्यक्रम लिखा है जो डेटाबेस से हजारों रिकॉर्ड वापस खींचता है, और उसके बाद उन प्रत्येक रिकॉर्ड पर एक-एक फ़ील्ड अपडेट करता है, एक-एक-एक। हमारी निराशा के लिए, हमने महसूस किया कि अद्यतन किए गए प्रत्येक रिकॉर्ड को उस समय की अवधि के लिए बंद कर दिया गया था जिसमें ऑब्जेक्ट कॉन्टेक्स्ट का निपटारा नहीं किया गया था। नीचे कुछ स्यूडोकोड (वास्तव में नहीं चलता है) वर्णन करने के लिए है:एंटीटी फ्रेमवर्क में डेटाबेस लॉक करने से कैसे बचें 4 कई अपडेट करते समय

using(ObjectContext context = new ObjectContext()) 
{ 

    var myRecords = context.CreateObjectSet<MyType>().AsQueryable(); 

    foreach(var record in myRecords) 
    { 
     record.MyField = "updated!"; 
     context.SaveChanges(); 

     //--do something really slow like call an external web service 
    } 
} 

समस्या यह है कि हम लेनदेन के लिए किसी भी संबंध के बिना कई अपडेट करने की ज़रूरत है। हम यह जानकर आश्चर्यचकित हुए कि संदर्भ को संदर्भित करना। सेव चेंज() वास्तव में रिकॉर्ड पर लॉक बनाता है और ऑब्जेक्ट कॉन्टेक्स्ट का निपटारा होने तक इसे रिलीज़ नहीं करता है। हम विशेष रूप से डेटाबेस में रिकॉर्ड्स लॉक नहीं करना चाहते हैं क्योंकि यह एक उच्च ट्रैफिक सिस्टम है और प्रोग्राम संभावित रूप से घंटों तक चल सकता है।

तो सवाल यह है कि: माइक्रोसॉफ्ट एंटीटी फ्रेमवर्क 4 में कई अपडेट करने का सबसे अच्छा तरीका क्या है जो उन्हें एक लंबे लेनदेन पर करने के लिए डीबी लॉक करता है? हम उम्मीद कर रहे हैं कि उत्तर प्रत्येक अद्यतन के लिए एक नया ऑब्जेक्ट कॉन्टेक्स्ट नहीं बनाना है ...

+0

क्या आप रिकॉर्ड लॉक देख रहे हैं या पृष्ठों या तालिकाओं में एस्केलेशन लॉक कर रहे हैं? –

+1

पूरी तालिका को लॉक किया गया प्रतीत होता है ताकि आप रिकॉर्ड डालें या अपडेट न कर सकें। हालांकि, आप रिकॉर्ड्स का चयन तब तक कर सकते हैं जब तक कि आप वापस रिकॉर्ड किए गए रिकॉर्ड्स में से एक का चयन न करें।हमारे छद्म उदाहरण में ऊपर हम सभी रिकॉर्ड वापस खींच लिया, हालांकि। हकीकत में, हम केवल कुल रिकॉर्ड के उप-सेट को वापस खींच रहे थे और केवल उन रिकॉर्ड को पढ़ने से बंद कर दिया गया था। हालांकि, पूरी तालिका लिखने से बंद है। – jakejgordon

उत्तर

7

डिफ़ॉल्ट रूप से एसक्यूएल सर्वर के शीर्ष पर इकाई फ्रेमवर्क पढ़ने के लिए प्रतिबद्ध लेनदेन अलगाव स्तर का उपयोग करता है और लेनदेन SaveChanges के अंत में किया जाता है। यदि आपको अन्य व्यवहार पर संदेह है तो यह आपके शेष कोड से होना चाहिए (क्या आप TransactionScope का उपयोग कर रहे हैं?- आपने इसे अपने कोड में नहीं दिखाया) या यह कुछ बग होना चाहिए।

इसके अलावा आपका दृष्टिकोण गलत है। यदि आप प्रत्येक रिकॉर्ड को अलग से सहेजना चाहते हैं तो आपको प्रत्येक रिकॉर्ड को अलग से लोड करना चाहिए। इस प्रकार के अनुप्रयोगों के लिए ईएफ निश्चित रूप से खराब विकल्प है। यहां तक ​​कि यदि आप अपने सभी रिकॉर्ड अपडेट करने के लिए केवल एक ही SaveChange का उपयोग करते हैं, तो भी यह प्रत्येक अपडेट के लिए डेटाबेस में सिंगल राउंडट्रिप बनाएगा।

+1

आपका दूसरा पैराग्राफ वही है जो हमने आखिरकार करने का फैसला किया था। हमने एक नया ऑब्जेक्ट कॉन्टेक्स्ट बनाने, रिकॉर्ड को पुनः प्राप्त करने, इसे अपडेट करने, इसे सहेजने और ऑब्जेक्ट कॉन्टेक्स्ट का निपटान समाप्त करने के लिए समाप्त किया ताकि प्रत्येक अपडेट अपने छोटे लेनदेन पर हो। वास्तव में इकाई फ्रेमवर्क इस तरह के आवेदन के लिए सबसे अच्छा समाधान नहीं प्रतीत होता है। –

2

मैं गलत हो सकता हूं, लेकिन मेरा मानना ​​है कि आपको प्रत्येक बार SaveChanges() को कॉल नहीं करना चाहिए क्योंकि इससे परिवर्तन लागू होते हैं उस बिंदु पर डेटाबेस। इसके बजाय, अपने ऑब्जेक्ट परिवर्तन के अंत में SaveChanges() लागू करें, या इसे कम बार करने के लिए काउंटर का उपयोग करें।

+0

आप सही हैं - हालांकि यह रिकॉर्ड पर लॉक जारी नहीं करता है। सवाल ऑब्जेक्ट कॉन्टेक्स्ट के पूरे जीवन चक्र के लिए ताला रखने के बिना तुरंत कैसे प्रतिबद्ध है, इस बारे में है। – jakejgordon

4

उन ताले एंटिटी फ्रेमवर्क द्वारा नहीं बनाए गए हैं। ईएफ केवल आशावादी समेकन का समर्थन करता है, निराशाजनक लॉकिंग ईएफ के साथ समर्थित नहीं है।

मुझे लगता है कि आपके द्वारा अनुभव किया गया लॉकिंग आपके SQL सर्वर कॉन्फ़िगरेशन का परिणाम है। शायद यदि सर्वर पर आपका लेनदेन अलगाव स्तर दोहराने के लिए सेट किया गया है तो यह प्रत्येक क्वेरी के बाद ताले का कारण बन सकता है। लेकिन मुझे यकीन नहीं है कि कौन सी कॉन्फ़िगरेशन सेटिंग वास्तव में समस्या हो सकती है। अधिक जानकारी here हैं।

संपादित करें:

एफई में लेनदेन और लेनदेन अलगाव के बारे में एक अन्य उपयोगी लेख here है। यह दृढ़ता से अलगाव स्तर को हमेशा सेट करने की दृढ़ता से अनुशंसा करता है। लेख से उद्धरण:

आप में पता नहीं है आप [ अलगाव स्तर], का नियंत्रण नहीं ले जो लेन-देन अलगाव स्तर अपने प्रश्नों चल रहा हो जाएगा करते हैं। आखिरकार, आपको पता नहीं है कि पूल से मिले कनेक्शन [...] आप कनेक्शन पर अलगाव स्तर के अंतिम उपयोग उत्तराधिकारी का उत्तराधिकारी प्राप्त करते हैं, इसलिए आपको पता नहीं है कि किस प्रकार के ताले को आपके प्रश्नों से लिया गया है (या इससे भी बदतर: अनदेखा) और इन लॉक कितने समय तक होंगे। एक व्यस्त डेटाबेस पर, यह निश्चित रूप से यादृच्छिक त्रुटियों का नेतृत्व करेगा, टाइम-आउट और डेडलॉक्स

+1

मैं प्रश्न पूछने वाले (एफवाईआई) का सहकर्मी हूं और मुझे समझ में नहीं आता कि यह मामला कैसे हो सकता है। जिस डेटाबेस में वह मार रहा है, उसके पास गैर-इकाई फ्रेमवर्क स्रोतों से प्रति सेकंड (YEARS) के दर्जनों अपडेट होते हैं और डीबी तक पहुंचने के लिए हमने इकाई फ्रेमवर्क का उपयोग करने से पहले कभी यह समस्या नहीं उठाई है .... हम नुकसान में हैं इस बिंदु। – jakejgordon

+0

@jakejgordon: क्या आप क्वेरी विंडो में 'DBCC USEROPTIONS' निष्पादित करके SQL सर्वर प्रबंधन स्टूडियो के लिए वर्तमान सेटिंग्स को जांच सकते हैं। इसमें कुछ सेटिंग्स सूचीबद्ध होनी चाहिए, उनमें से एक 'अलगाव स्तर' है। डिफ़ॉल्ट रूप से इसे "पढ़ाया जाना चाहिए" होना चाहिए। क्या आपके पास शायद एक और सेटिंग है? – Slauma

+0

अलगाव स्तर "पढ़ा गया" है। वैसे भी आपकी मदद के लिए धन्यवाद, हम वास्तव में इसकी सराहना करते हैं! – jakejgordon

1

हमारे आवेदन में हमारे पास एक समान परिदृश्य था, जितना संभव हो सके बड़े पैमाने पर चयन करने के लिए लॉकिंग से बचें और फिर कुछ मेमोरी ऑपरेशन के बाद कई प्रविष्टियां बनाएं।

  1. तुम सब कुछ अग्रिम

समाधान एक) का उपयोग करें पढ़ने के लिए एक सौदे गुंजाइश है कि पढ़ भी शामिल है और अद्यतन प्रो चाहते हैं: डेटा को सुरक्षित रूप से अद्यतन कान्स: पढ़ने की वजह से ताले (दोहराने योग्य पढ़ता है) और

समाधान बी) लेनदेन का उपयोग न करें और सभी डेटा को एक साथ अपडेट करें PRO: डेटा सुरक्षित रूप से अपडेट किया गया है, लेकिन डेटा पढ़ने इस बीच कान्स में बदल दी गई हैं: पूरी अवधि के लिए अद्यतन (एफई डिफ़ॉल्ट रूप से कोई लेन-देन बनाने)

समाधान सी की वजह से ताले) सभी डेटा के बजाय बैचों में अद्यतन सब एक साथ (प्रयोग करने योग्य केवल यदि चयन टेबल को लॉक नहीं कर रहा है, अन्यथा आपको बी प्रो के समान व्यवहार मिलता है: अद्यतन तालिकाओं में छोटे और छोटे ताले CONS: आप डेटा अड़चन से प्रभावित होने के परिवर्तन को बढ़ाते हैं

  1. यदि आप बैचों में पढ़ना चाहते हैं (और कर सकते हैं)

समाधान डी) समस्या को तोड़ना और पढ़ने को विभाजित करना आपको लॉक को कम करने में सुविधा प्रदान कर सकता है ताकि आप पढ़ने और लिखने के लिए एक लेनदेन के दायरे का उपयोग कर सकें (जैसे सोल। ए) प्रो: डेटा को सुरक्षित रूप से कान्स अद्यतन: ताले (दोहराने योग्य पढ़ता है) और अद्यतन पढ़ने की वजह से, प्रभावों बैच आकार और क्वेरी ही

समाधान ई) लेनदेन का प्रयोग न करें की प्रकृति के आधार पर भिन्न है, इसलिए केवल अद्यतन छोटे ताले उत्पादन करेगा (के रूप में सोल बी।) प्रो: डेटा को सुरक्षित रूप से अपडेट किया है, लेकिन डेटा आप पढ़ सकते हैं इस बीच कान्स में बदल दी गई हैं: अद्यतन

रूप @Ladislav सही ढंग से बताया की वजह से ताले , एकाधिक आवेषण वास्तव में अक्षम हैं और डेटाबेस पर त्वरित प्रोफाइलिंग आपको दिखाती है कि इस मामले में ओआरएम जादू कैसे विफल रहता है। आप एफई उपयोग करने के लिए बैच कार्रवाई ऐसे आवेषण, अद्यतन और हटाए गए प्रदर्शन करने के लिए चाहते हैं, तो मैं सुझाव है कि आप इस पर एक नज़र है करने के लिए: EF Utilities

मैं इस क्वेरी का उपयोग ताले का परीक्षण करने के लिए करते हैं, मुझे आशा है कि बेहतर ढंग से समझने में मदद मिल सकती क्या हो रहा है।

SELECT 
    OBJECT_NAME(p.OBJECT_ID) AS TableName, 
    resource_type, 
    resource_description 
FROM 
    sys.dm_tran_locks l JOIN 
    sys.partitions p ON 
    l.resource_associated_entity_id = p.hobt_id 
संबंधित मुद्दे