यह सवाल "जो मुझे ओआरएम का उपयोग करना चाहिए" वास्तव में एक विशाल हिमशैल के टिप को लक्षित कर रहा है जब यह बड़े पैमाने पर आवेदन में समग्र डेटा एक्सेस रणनीति और प्रदर्शन अनुकूलन की बात आती है।
डेटाबेस डिजाइन और रखरखाव
यह एक विस्तृत मार्जिन द्वारा, डेटा-संचालित एप्लिकेशन या वेब साइट के थ्रूपुट का एकल सबसे महत्वपूर्ण निर्धारक है, और अक्सर प्रोग्रामर द्वारा पूरी तरह से अनदेखा किया जाता है।
यदि आप उचित सामान्यीकरण तकनीकों का उपयोग नहीं करते हैं, तो आपकी साइट बर्बाद है। यदि आपके पास प्राथमिक कुंजियाँ नहीं हैं, तो लगभग हर क्वेरी डॉग-स्लो होगी। यदि आप बिना किसी अच्छे कारण के जाने-माने एंटी-पैटर्न का उपयोग करते हैं जैसे कि की-वैल्यू पेयर (एके एंटिटी-एट्रीब्यूट-वैल्यू) के लिए तालिकाओं का उपयोग करते हैं, तो आप भौतिक रीड और लिखने की संख्या में विस्फोट करेंगे।
यदि आप उन सुविधाओं का लाभ नहीं उठाते हैं जो डेटाबेस आपको देता है, जैसे पृष्ठ संपीड़न, FILESTREAM
भंडारण (बाइनरी डेटा के लिए), SPARSE
कॉलम, hierarchyid
पदानुक्रम के लिए, और इसी तरह (सभी SQL सर्वर उदाहरण), तो आप कहीं भी पास नहीं देखेंगे प्रदर्शन जिसे आप देख सकते हैं।
आपको अपने डेटाबेस को डिज़ाइन करने के बाद अपनी डेटा एक्सेस रणनीति के बारे में चिंता करना शुरू कर देना चाहिए और अपने आप को आश्वस्त करना चाहिए कि यह जितना संभव हो उतना अच्छा है, कम से कम समय के लिए हो सकता है।
उत्सुक बनाम आलसी लोड हो रहा है
अधिकांश ORM ने रिश्तों के लिए आलसी लोडिंग नामक एक तकनीक का उपयोग किया , जिसका अर्थ है कि डिफ़ॉल्ट रूप से यह एक समय में एक इकाई (तालिका पंक्ति) को लोड करेगा, और हर बार डेटाबेस में एक या कई संबंधित (लोड करने के लिए) की आवश्यकता होती है। कुंजी) पंक्तियाँ।
यह अच्छी या बुरी बात नहीं है, यह इस बात पर निर्भर करता है कि वास्तव में डेटा के साथ क्या किया जाना है, और आप कितना जानते हैं। कभी-कभी आलसी-लोडिंग करना बिल्कुल सही काम है। उदाहरण के लिए, NHibernate किसी भी चीज़ के लिए क्वेरी नहीं करने का निर्णय ले सकता है और बस किसी विशेष आईडी के लिए एक प्रॉक्सी उत्पन्न कर सकता है । यदि आपको कभी भी आईडी की आवश्यकता होती है, तो इसे और अधिक के लिए क्यों पूछना चाहिए? दूसरी ओर, यदि आप 3-स्तरीय पदानुक्रम में हर एक तत्व के पेड़ को प्रिंट करने की कोशिश कर रहे हैं, तो आलसी-लोडिंग एक ओ (एन loading) ऑपरेशन बन जाता है, जो प्रदर्शन के लिए बेहद खराब है।
"शुद्ध एसक्यूएल" (यानी कच्चे ADO.NET प्रश्न / संग्रहीत प्रक्रियाओं) का उपयोग करने का एक दिलचस्प लाभ यह है कि यह मूल रूप से आपको यह सोचने के लिए मजबूर करता है कि किसी दिए गए स्क्रीन या पृष्ठ को प्रदर्शित करने के लिए क्या डेटा आवश्यक है। ORMs और आलसी लोडिंग सुविधाओं नहीं है को रोकने के ऐसा करने से आप, लेकिन वे करते हैं आप होने के लिए ... अच्छी तरह से, अवसर देते हैं आलसी , और गलती से प्रश्नों आप पर अमल की संख्या में विस्फोट। इसलिए आपको अपने ORM की उत्सुक-लोडिंग सुविधाओं को समझने की आवश्यकता है और किसी भी पृष्ठ अनुरोध के लिए सर्वर को भेजे जाने वाले प्रश्नों की संख्या के बारे में सतर्क रहें।
कैशिंग
सभी प्रमुख ORM पहले स्तर के कैश, AKA "पहचान कैश" को बनाए रखते हैं, जिसका अर्थ है कि यदि आप एक ही इकाई को दो बार अपनी आईडी से अनुरोध करते हैं, तो उसे दूसरे दौर की यात्रा की आवश्यकता नहीं है, और (यदि आपने अपने डेटाबेस को सही तरीके से डिज़ाइन किया है) ) आपको आशावादी संगामिति का उपयोग करने की क्षमता देता है।
L1 कैश L2S और EF में काफी अपारदर्शी है, आपको भरोसा है कि यह काम कर रहा है। NHibernate इसके बारे में अधिक स्पष्ट है ( Get
/ Load
बनाम Query
/ QueryOver
)। फिर भी, जब तक आप जितना संभव हो आईडी द्वारा क्वेरी करने का प्रयास करते हैं, आपको यहां ठीक होना चाहिए। बहुत सारे लोग L1 कैश के बारे में भूल जाते हैं और बार-बार एक ही इकाई को अपनी आईडी (यानी एक लुकअप) के अलावा किसी अन्य चीज़ से बार-बार देखते हैं। यदि आपको ऐसा करने की आवश्यकता है, तो आपको भविष्य के लुकअप के लिए आईडी या यहां तक कि पूरी इकाई को सहेजना चाहिए।
एक स्तर 2 कैश ("क्वेरी कैश") भी है। NHibernate में यह बिल्ट-इन है। Linq to SQL और Entity Framework ने प्रश्नों को संकलित किया है , जो कि क्वेरी एक्सप्रेशन को स्वयं संकलित करके ऐप सर्वर लोड को काफी कम करने में मदद कर सकता है, लेकिन यह डेटा को कैश नहीं करता है। Microsoft इसे डेटा-एक्सेस चिंता के बजाय एक एप्लिकेशन चिंता का विषय मानता है, और यह L2S और EF दोनों का एक प्रमुख कमजोर बिंदु है। कहने की जरूरत नहीं है कि यह "रॉ" एसक्यूएल का एक कमजोर बिंदु भी है। मूल रूप से NHibernate के अलावा किसी भी ORM के साथ वास्तव में अच्छा प्रदर्शन पाने के लिए, आपको अपने स्वयं के कैशिंग फाकेड को लागू करने की आवश्यकता है।
EF4 के लिए एक L2 कैश "एक्सटेंशन" भी है जो ठीक है , लेकिन एप्लिकेशन-स्तर कैश के लिए वास्तव में एक थोक प्रतिस्थापन नहीं है।
क्वेरी की संख्या
रिलेशनल डेटाबेस डेटा के सेट पर आधारित होते हैं । वे कम समय में बड़ी मात्रा में डेटा का उत्पादन करने में वास्तव में अच्छे हैं , लेकिन वे क्वेरी विलंबता के मामले में कहीं भी अच्छे नहीं हैं क्योंकि हर कमांड में एक निश्चित मात्रा में ओवरहेड शामिल है। एक अच्छी तरह से डिज़ाइन किया गया ऐप इस DBMS की ताकत के लिए खेलना चाहिए और प्रश्नों की संख्या को कम करने और प्रत्येक में डेटा की मात्रा को अधिकतम करने का प्रयास करना चाहिए।
अब मैं पूरे डेटाबेस को क्वेरी करने के लिए नहीं कह रहा हूं जब आपको केवल एक पंक्ति की आवश्यकता होती है। अगर आप की जरूरत है, जो मैं कह रहा हूँ है Customer
, Address
, Phone
, CreditCard
, और Order
एक ही पृष्ठ प्रदर्शित करने के लिए एक ही समय में सभी पंक्तियों, तो आप चाहिए पूछना , एक ही समय में उन सब के लिए अलग से प्रत्येक क्वेरी को निष्पादित नहीं है। कभी-कभी यह उससे भी बदतर होता है, आप एक ही Customer
बार में 5 बार एक ही रिकॉर्ड करने वाले कोड को देखेंगे , पहले प्राप्त करने के लिए Id
, फिर Name
, फिर EmailAddress
, फिर ... यह हास्यास्पद रूप से अक्षम है।
यहां तक कि अगर आपको कई प्रश्नों को निष्पादित करने की आवश्यकता होती है, जो सभी डेटा के पूरी तरह से अलग-अलग सेटों पर काम करते हैं, तो यह आम तौर पर सभी को एक "स्क्रिप्ट" के रूप में डेटाबेस में भेजने के लिए अधिक कुशल होता है और इसके कई परिणाम सेट लौटाते हैं। यह वह ओवरहेड है जिसके साथ आप चिंतित हैं, डेटा की कुल राशि नहीं।
यह सामान्य ज्ञान की तरह लग सकता है लेकिन आवेदन के विभिन्न भागों में निष्पादित होने वाले सभी प्रश्नों का ट्रैक खोना वास्तव में बहुत आसान है; आपका सदस्यता प्रदाता उपयोगकर्ता / भूमिका तालिकाओं पर सवाल उठाता है, आपका हैडर एक्शन खरीदारी की टोकरी पर सवाल उठाता है, आपकी मेनू कार्रवाई साइट मानचित्र तालिका पर सवाल उठाता है, आपकी साइडबार कार्रवाई में फ़ीचर्ड उत्पाद सूची पर सवाल उठाता है, और फिर शायद आपके पृष्ठ को कुछ अलग स्वायत्त क्षेत्रों में विभाजित किया जाता है जो ऑर्डर इतिहास, हाल ही में देखे गए, श्रेणी और सूची सारणी को अलग से क्वेरी करें, और इससे पहले कि आप इसे जानें, इससे पहले कि आप पृष्ठ की सेवा शुरू कर सकें, इससे पहले आप 20 प्रश्नों को निष्पादित कर रहे हैं। यह पूरी तरह से प्रदर्शन को नष्ट कर देता है।
कुछ चौखटे - और मैं यहां मुख्य रूप से NHibernate के बारे में सोच रहा हूं - इस बारे में अविश्वसनीय रूप से चतुर हैं और आपको फ्यूचर नामक कुछ का उपयोग करने की अनुमति देते हैं जो पूरे प्रश्नों को बैचते हैं और उन सभी को अंतिम समय पर एक बार में निष्पादित करने का प्रयास करते हैं। AFAIK, यदि आप Microsoft तकनीकों में से किसी के साथ ऐसा करना चाहते हैं, तो आप अपने दम पर हैं; आपको इसे अपने एप्लिकेशन लॉजिक में बनाना होगा।
अनुक्रमण, विधेय और अनुमान
कम से कम 50% देवों से मैं बात करता हूं और यहां तक कि कुछ डीबीए को भी अनुक्रमणिका को कवर करने की अवधारणा से परेशानी होती है। वे सोचते हैं, "ठीक है, Customer.Name
कॉलम को अनुक्रमित किया गया है, इसलिए मैं नाम पर प्रत्येक लुकअप फास्ट होना चाहिए।" सिवाय इसके कि यह उस तरह से काम नहीं करता है जब तक कि Name
सूचकांक आपके द्वारा देखे जा रहे विशिष्ट कॉलम को कवर नहीं करता है । SQL सर्वर में, यह कथन INCLUDE
में किया गया CREATE INDEX
है।
यदि आप SELECT *
हर जगह भोलेपन का उपयोग करते हैं - और यह कमोबेश हर ओआरएम क्या करेगा जब तक आप स्पष्ट रूप से अन्यथा एक प्रक्षेपण का उपयोग करते हुए निर्दिष्ट नहीं करते हैं - तब डीबीएमएस बहुत अच्छी तरह से आपके अनुक्रमितों को पूरी तरह से अनदेखा करने का विकल्प चुन सकते हैं क्योंकि उनमें गैर-कवर किए गए कॉलम होते हैं। एक प्रक्षेपण का अर्थ है, उदाहरण के लिए, ऐसा करने के बजाय:
from c in db.Customers where c.Name == "John Doe" select c
आप इसके बजाय ऐसा करें:
from c in db.Customers where c.Name == "John Doe"
select new { c.Id, c.Name }
और यह होगा, सबसे आधुनिक ORMs के लिए, हिदायत यह केवल जाने के लिए और क्वेरी करने के लिए Id
और Name
कॉलम जो संभवतः सूचकांक के अंतर्गत आते हैं (लेकिन नहीं Email
, LastActivityDate
, या कोई अन्य स्तंभों तुम वहाँ में रहना हुआ)।
अनुचित विधेय का उपयोग करके किसी भी अनुक्रमण लाभों को पूरी तरह से दूर करना भी बहुत आसान है। उदाहरण के लिए:
from c in db.Customers where c.Name.Contains("Doe")
... लगभग हमारी पिछली क्वेरी के समान है, लेकिन वास्तव में इसका परिणाम पूर्ण तालिका या इंडेक्स स्कैन में होगा क्योंकि यह अनुवाद करता है LIKE '%Doe%'
। इसी तरह, एक और क्वेरी जो संदिग्ध रूप से सरल लगती है:
from c in db.Customers where (maxDate == null) || (c.BirthDate >= maxDate)
यह मानते हुए कि आपके पास एक इंडेक्स है BirthDate
, इस विधेय के पास इसे पूरी तरह से बेकार करने का अच्छा मौका है। हमारे काल्पनिक प्रोग्रामर ने स्पष्ट रूप से एक प्रकार की गतिशील क्वेरी बनाने का प्रयास किया है ("केवल जन्म तिथि को फ़िल्टर करें यदि वह पैरामीटर निर्दिष्ट किया गया था"), लेकिन ऐसा करने का यह सही तरीका नहीं है। इसके बजाय इस तरह लिखा गया है:
from c in db.Customers where c.BirthDate >= (maxDate ?? DateTime.MinValue)
... अब DB इंजन जानता है कि इसे कैसे परिमाणित करना है और एक सूचकांक की तलाश है। क्वेरी अभिव्यक्ति में एक मामूली, प्रतीत होता है नगण्य परिवर्तन प्रदर्शन को काफी प्रभावित कर सकता है।
दुर्भाग्य से LINQ सामान्य रूप से इस तरह के बुरे प्रश्नों को लिखना बहुत आसान बनाता है क्योंकि कभी-कभी प्रदाता यह अनुमान लगाने में सक्षम होते हैं कि आप क्वेरी को करने और अनुकूलित करने के लिए क्या प्रयास कर रहे थे, और कभी-कभी वे नहीं होते हैं। तो आप निराशाजनक रूप से असंगत परिणामों के साथ समाप्त होते हैं जो स्पष्ट रूप से स्पष्ट (एक अनुभवी डीबीए के लिए, वैसे भी) होगा जो आपने अभी-अभी सादे पुराने एसक्यूएल को लिखा था।
मूल रूप से यह सब इस तथ्य पर उतरता है कि आपको वास्तव में उत्पन्न एसक्यूएल और निष्पादन योजनाओं दोनों पर कड़ी नजर रखनी होगी और यदि आप उन परिणामों को प्राप्त नहीं कर रहे हैं जिनकी आपको उम्मीद है, तो डरें नहीं। ORM लेयर को एक बार और SQL को हैंड-कोड करें। यह किसी भी ORM के लिए जाता है , न कि केवल EF के लिए।
लेन-देन और ताला
क्या आपको मिलीसेकंड तक मौजूद डेटा को प्रदर्शित करने की आवश्यकता है? शायद - यह निर्भर करता है - लेकिन शायद नहीं। अफसोस की बात है कि, एंटिटी फ्रेमवर्क आपको नहीं देता हैnolock
, आप केवल लेनदेन स्तर (तालिका स्तर नहीं) READ UNCOMMITTED
पर उपयोग कर सकते हैं । वास्तव में कोई भी ORM इस बारे में विशेष रूप से विश्वसनीय नहीं है; यदि आप गंदे रीडिंग करना चाहते हैं, तो आपको एसक्यूएल स्तर तक गिरना होगा और एड-हॉक क्वेरी या स्टोर की गई प्रक्रियाओं को लिखना होगा। तो क्या यह उबलता है, फिर से, आपके लिए फ्रेमवर्क के भीतर यह करना कितना आसान है।
एंटिटी फ्रेमवर्क ने इस संबंध में एक लंबा सफर तय किया है - ईएफ का संस्करण 1 (.NET 3.5 में) ईश्वर-विस्मयकारी था, जिससे "संस्थाओं" अमूर्त के माध्यम से तोड़ना अविश्वसनीय रूप से कठिन हो गया, लेकिन अब आपके पास ExecuteStoreQuery और अनुवाद है , इसलिए यह वास्तव में है इतना भी बेकार नहीं। इन लोगों से दोस्ती करें क्योंकि आप इनका भरपूर इस्तेमाल करेंगे।
वहाँ भी लेखन ताला और गतिरोध के मुद्दे और संभव के रूप में कम से कम समय के लिए डेटाबेस में ताले धारण करने की प्रथा है। इस संबंध में, अधिकांश ओआरएम (एंटिटी फ्रेमवर्क सहित) वास्तव में कच्चे एसक्यूएल से बेहतर होते हैं क्योंकि वे वर्क पैटर्न की इकाई को एन्क्रिप्ट करते हैं , जो कि ईएफ में सेवचेंज होता है । दूसरे शब्दों में, आप अपने दिल की सामग्री के लिए "इन्सर्ट" या "अपडेट" या "डिलीट" एंटिटीज कर सकते हैं, जब भी आप चाहें, इस ज्ञान में सुरक्षित रहें कि कोई भी परिवर्तन वास्तव में डेटाबेस में तब तक नहीं धकेला जाएगा जब तक आप कार्य की इकाई नहीं बनाते हैं।
ध्यान दें कि एक UOW लंबे समय तक चलने वाले लेनदेन के अनुरूप नहीं है । UOW अभी भी ORM की आशावादी संगामिति सुविधाओं का उपयोग करता है और स्मृति में सभी परिवर्तनों को ट्रैक करता है । अंतिम प्रतिबद्ध होने तक एक भी DML कथन उत्सर्जित नहीं होता है। इससे लेनदेन का समय कम से कम रहता है। यदि आप कच्चे SQL का उपयोग करके अपना एप्लिकेशन बनाते हैं, तो इस स्थगित व्यवहार को प्राप्त करना काफी मुश्किल है।
विशेष रूप से ईएफ के लिए इसका क्या मतलब है: अपनी इकाइयों को जितना संभव हो सके उतना कठिन बनाएं और जब तक आपको बिल्कुल ज़रूरत न हो, तब तक उन्हें प्रतिबद्ध न करें। ऐसा करें और आप यादृच्छिक समय पर व्यक्तिगत ADO.NET कमांड का उपयोग करने की तुलना में बहुत कम लॉक विवाद के साथ समाप्त करेंगे।
उच्च ट्रैफ़िक / उच्च-प्रदर्शन अनुप्रयोगों के लिए EF पूरी तरह से ठीक है, ठीक उसी तरह जैसे हर दूसरा फ्रेमवर्क उच्च-ट्रैफ़िक / उच्च-प्रदर्शन अनुप्रयोगों के लिए ठीक है। क्या मायने रखता है कि आप इसका उपयोग कैसे करते हैं। यहां सबसे लोकप्रिय फ्रेमवर्क की त्वरित तुलना है और वे प्रदर्शन के संदर्भ में क्या विशेषताएं प्रदान करते हैं (किंवदंती: एन = समर्थित नहीं, पी = आंशिक, वाई = हाँ / समर्थित):
जैसा कि आप देख सकते हैं, EF4 (वर्तमान संस्करण) बहुत बुरी तरह से किराया नहीं करता है, लेकिन संभवतः यह सबसे अच्छा नहीं है यदि प्रदर्शन आपकी प्राथमिक चिंता है। NHibernate इस क्षेत्र में बहुत अधिक परिपक्व है और यहां तक कि Linq to SQL कुछ प्रदर्शन-बढ़ाने वाली सुविधाएँ प्रदान करता है जो EF अभी भी नहीं करता है। रॉ ADO.NET अक्सर बहुत विशिष्ट डेटा-एक्सेस परिदृश्यों के लिए तेज़ होने वाला है, लेकिन, जब आप सभी टुकड़ों को एक साथ रखते हैं, तो यह वास्तव में बहुत सारे महत्वपूर्ण लाभों की पेशकश नहीं करता है जो आपको विभिन्न रूपरेखाओं से मिलते हैं।