तैयार किए गए SQL बैच को निष्पादित करने से अलग एक SQL बैच तैयार करना एक निर्माण है जो प्रभावी रूप से ** है SQL सर्वर के लिए बेकार है, यह देखते हुए कि निष्पादन योजनाओं को कैसे कैश किया जाता है। तैयारी के चरणों को अलग करना (पार्स करना, किसी भी पैरामीटर को बांधना और संकलन करना) और निष्पादन केवल तभी समझ में आता है जब कोई कैशिंग नहीं होता है। उद्देश्य मौजूदा योजना का पुन: उपयोग करके पार्सिंग और संकलन पर खर्च किए गए समय को बचाना है, और यही आंतरिक योजना कैश करती है। लेकिन सभी RDBMS इस तरह के कैशिंग (इन कार्यों के अस्तित्व से स्पष्ट रूप से) नहीं करते हैं और इसलिए यह ग्राहक कोड के लिए छोड़ दिया जाता है ताकि यह अनुरोध किया जा सके कि एक योजना "कैश्ड" हो, और इसलिए उस कैश आईडी को सहेजें, और फिर से उपयोग करें यह। यह ग्राहक कोड पर अतिरिक्त बोझ है (और प्रोग्रामर को इसे करने के लिए याद रखना और इसे ठीक करना) जो अनावश्यक है। असल में,IDbCommand.Prepare () विधि राज्यों के :
सर्वर स्वचालित रूप से आवश्यक के रूप में पुन: उपयोग के लिए योजना को कैश करता है; इसलिए, इस विधि को सीधे आपके क्लाइंट एप्लिकेशन में कॉल करने की आवश्यकता नहीं है।
यह ध्यान दिया जाना चाहिए कि, जहाँ तक मेरा परीक्षण दिखाता है (जो कि आप प्रश्न में दिखाते हैं), SqlCommand.Prepare () को कॉल करते हुए, एक "तैयारी" नहीं करता है- केवल ऑपरेशन: यह कॉल करता है sp_prepexec - SQL को तैयार और निष्पादित करता है ; यह sp_prepare को कॉल नहीं करता है जो केवल पार्स है और संकलन करता है (और किसी भी पैरामीटर मान में नहीं लेता है, केवल उनके नाम और डेटाटिप्स)। इसलिए, कॉल करने का कोई "पूर्व-संकलन" लाभ नहीं हो सकता है SqlCommand.Prepare
क्योंकि यह एक तत्काल निष्पादन करता है (लक्ष्य को निष्पादन को स्थगित करना है)। फिर भी , SqlCommand.Prepare()
कॉल sp_prepexec
करने का एक दिलचस्प संभावित मामूली लाभ है , भले ही वह इसके बजाय कॉल करता हो sp_prepare
। कृपया नोट देखें (** ) विवरण के लिए नीचे।
मेरे परीक्षण से पता चलता है कि जब SqlCommand.Prepare()
भी कॉल किया जाता है (और कृपया ध्यान दें कि यह कॉल SQL सर्वर पर कोई आदेश जारी नहीं करता है ), ExecuteNonQuery
या ExecuteReader
जो इस प्रकार पूरी तरह से निष्पादित होता है, और यदि यह ExecuteReader है, तो यह पंक्तियों को लौटाता है। फिर भी, SQL सर्वर प्रोफाइलर दिखाता है कि SqlCommand.Execute______()
कॉल के बाद पहला कॉल SqlCommand.Prepare()
"SQL तैयार करें" ईवेंट के .Execute___()
रूप में पंजीकृत होता है , और बाद में कॉल "Exec Ready SQL" ईवेंट के रूप में रजिस्टर होता है।
टेस्ट कोड
इसे PasteBin पर: http://pastebin.com/Yc2Tfvup पर अपलोड किया गया है । कोड एक .NET / C # कंसोल ऐप बनाता है, जो एक SQL Server Profiler ट्रेस चल रहा है (या एक विस्तारित ईवेंट सत्र) चलाने के लिए अभिप्रेत है। यह प्रत्येक चरण के बाद रुक जाता है इसलिए यह स्पष्ट हो जाएगा कि किन बयानों का एक विशेष प्रभाव है।
अपडेट करें
अधिक जानकारी मिली, और कॉल से बचने के लिए एक मामूली संभावित कारण SqlCommand.Prepare()
। एक बात जो मैंने अपने परीक्षण में देखी, और उस परीक्षण कंसोल ऐप को चलाने वाले किसी के लिए क्या ध्यान दिया जाना चाहिए: कोई स्पष्ट कॉल नहीं किया गया sp_unprepare
। मैंने कुछ खुदाई की और MSDN मंचों में निम्नलिखित पोस्ट पाया:
SqlCommand - तैयार करने के लिए या नहीं?
स्वीकृत उत्तर में जानकारी का एक समूह होता है, लेकिन मुख्य बिंदु निम्न हैं:
- ** क्या तैयारी वास्तव में बचाता है आप मुख्य रूप से तार पर क्वेरी स्ट्रिंग को प्रसारित करने में लगने वाला समय है।
- तैयार क्वेरी में कैश्ड प्लान के सेव होने की कोई गारंटी नहीं है, और यह सर्वर तक पहुँचने के बाद किसी ऐड-हॉक क्वेरी से तेज़ नहीं है।
- RPC की कमांड (CommandType.StoredProcedure) तैयारी से कुछ भी हासिल नहीं करती है।
- सर्वर पर, एक तैयार किया गया हैंडल मूल रूप से एक इन-मेमोरी मैप में एक इंडेक्स होता है जिसमें निष्पादित करने के लिए TSQL होता है।
- नक्शा प्रति-कनेक्शन के आधार पर संग्रहीत किया जाता है, कोई क्रॉस-कनेक्शन उपयोग संभव नहीं है।
- क्लाइंट द्वारा पूल से कनेक्शन का पुन: उपयोग करने पर भेजा गया रीसेट मैप को साफ करता है।
मैंने SQLCAT टीम से निम्न पोस्ट भी पाया, जो संबंधित प्रतीत होता है, लेकिन यह केवल ODBC के लिए एक समस्या हो सकती है जबकि SqlClient SqlConnection के निपटान पर सही ढंग से सफाई करता है। यह कहना मुश्किल है क्योंकि SQLCAT पोस्ट में किसी भी अतिरिक्त परीक्षण का उल्लेख नहीं है जो इसे एक कारण के रूप में साबित करने में मदद करेगा, जैसे कि कनेक्शन पूल को साफ करना, आदि।
उन तैयार किए गए एसक्यूएल बयानों को देखें
निष्कर्ष
मान लीजिये:
- कॉलिंग का एकमात्र वास्तविक लाभ यह
SqlCommand.Prepare()
प्रतीत होता है कि आपको नेटवर्क पर फिर से क्वेरी टेक्स्ट सबमिट करने की आवश्यकता नहीं है,
- कनेक्शन की मेमोरी (यानी SQL सर्वर मेमोरी) के हिस्से के रूप में क्वेरी टेक्स्ट को कॉल
sp_prepare
और sp_prepexec
स्टोर करना
मैं कॉल करने के खिलाफ सिफारिश करूंगा SqlCommand.Prepare()
क्योंकि केवल संभावित लाभ नेटवर्क पैकेट को बचा रहा है जबकि नकारात्मक पक्ष अधिक सर्वर मेमोरी ले रहा है। जबकि अधिकांश मामलों में खपत की गई मेमोरी संभवतः बहुत कम है, नेटवर्क बैंडविड्थ शायद ही कभी एक समस्या है क्योंकि अधिकांश डीबी सर्वर सीधे 10 मेगाबिट न्यूनतम (अधिक संभावना 100 मेगाबिट या गीगाबिट इन दिनों) कनेक्शन पर ऐप सर्वर से जुड़े होते हैं ( और कुछ एक ही बॉक्स पर भी ;-) यह और मेमोरी लगभग हमेशा नेटवर्क बैंडविड्थ की तुलना में अधिक दुर्लभ संसाधन है।
मुझे लगता है, सॉफ्टवेयर लिखने वाले किसी भी व्यक्ति के लिए, जो कई डेटाबेस से जुड़ सकता है, फिर एक मानक इंटरफ़ेस की सुविधा इस लागत / लाभ विश्लेषण को बदल सकती है। लेकिन उस मामले में भी, मेरा मानना है कि "मानक" DB इंटरफ़ेस को अमूर्त करना काफी आसान है जो विभिन्न प्रदाताओं के लिए अनुमति देता है (और इसलिए उनके बीच अंतर, जैसे कॉल करने की आवश्यकता नहीं है Prepare()
) यह देखते हुए कि ऐसा करना मूल वस्तु है ओरिएंटेड प्रोग्रामिंग जो आप अपने ऐप कोड में पहले से कर रहे हैं ;-)।