2010-03-15 8 views
32

जब मैं किताबें सी # जानने के लिए पढ़ रहा था (कुछ पुराने Visual Studio 2005 किताबें हो सकता है) मैं सलाह का सामना किया है हमेशा SqlCommand.Prepare हर उपयोग करने के लिए मैं एसक्यूएल कॉल पर अमल (चाहे अपनी 'एक SELECT/UPDATE या INSERT एसक्यूएल सर्वर 2005/2008 पर) और मैं इसके पैरामीटर पास करता हूं। लेकिन क्या यह वास्तव में है?SqlCommand का उपयोग करने के पेशेवरों और विपक्ष सी # में तैयार हैं?

  1. यह हर बार किया जाना चाहिए? या कभी कभी कभी?

  2. क्या इससे कोई फर्क पड़ता है कि यह एक पैरामीटर पारित किया गया है या पांच या बीस?

  3. यदि कोई हो तो उसे क्या बढ़ावा देना चाहिए? क्या यह बिल्कुल ध्यान देने योग्य होगा (मैं यहां SqlCommand.Prepare का उपयोग कर रहा हूं और इसे वहां छोड़ दिया है और कभी भी कोई समस्या या ध्यान देने योग्य मतभेद नहीं थे)।

प्रश्न के लिए यह मेरा सामान्य कोड है जिसका उपयोग मैं करता हूं, लेकिन यह एक सामान्य प्रश्न है।

public static decimal pobierzBenchmarkKolejny(string varPortfelID, DateTime data, decimal varBenchmarkPoprzedni, decimal varStopaOdniesienia) { 
    const string preparedCommand = @"SELECT [dbo].[ufn_BenchmarkKolejny](@varPortfelID, @data, @varBenchmarkPoprzedni, @varStopaOdniesienia) AS 'Benchmark'"; 
    using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) //if (varConnection != null) { 
    using (var sqlQuery = new SqlCommand(preparedCommand, varConnection)) { 
     sqlQuery.Prepare(); 
     sqlQuery.Parameters.AddWithValue("@varPortfelID", varPortfelID); 
     sqlQuery.Parameters.AddWithValue("@varStopaOdniesienia", varStopaOdniesienia); 
     sqlQuery.Parameters.AddWithValue("@data", data); 
     sqlQuery.Parameters.AddWithValue("@varBenchmarkPoprzedni", varBenchmarkPoprzedni); 
     using (var sqlQueryResult = sqlQuery.ExecuteReader()) 
      if (sqlQueryResult != null) { 
       while (sqlQueryResult.Read()) { 

       } 
      } 
    } 
} 

अतिरिक्त स्पष्टीकरण:

तो मैं अपवाद नीचे कोड में की तरह sqlQuery.Prepare() ले जाने के फेंक दिया जाता है आकार स्पष्ट रूप से घोषित किया जाना है, जो मूल रूप से मुझे यह सोच कर कि होने sqlQuery.Prepare() के रूप में पहली यह बेकार बना देता है की प्राप्ति होती है कि? क्या कोई मेरे उदाहरण का उपयोग करके उचित उपयोग दिखा सकता है?

public static decimal pobierzBenchmarkKolejny(string varPortfelID, DateTime data, decimal varBenchmarkPoprzedni, decimal varStopaOdniesienia) { 
    const string preparedCommand = @"SELECT [dbo].[ufn_BenchmarkKolejny](@varPortfelID, @data, @varBenchmarkPoprzedni, @varStopaOdniesienia) AS 'Benchmark'"; 
    using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) //if (varConnection != null) { 
    using (var sqlQuery = new SqlCommand(preparedCommand, varConnection)) { 

     sqlQuery.Parameters.AddWithValue("@varPortfelID", varPortfelID); 
     sqlQuery.Parameters.AddWithValue("@varStopaOdniesienia", varStopaOdniesienia); 
     sqlQuery.Parameters.AddWithValue("@data", data); 
     sqlQuery.Parameters.AddWithValue("@varBenchmarkPoprzedni", varBenchmarkPoprzedni); 
     sqlQuery.Prepare(); 
     using (var sqlQueryResult = sqlQuery.ExecuteReader()) 
      if (sqlQueryResult != null) { 
       while (sqlQueryResult.Read()) { 

       } 
      } 
    } 
} 

मैं यह कैसे करूँगा? पैरामीटर के बगल में .size जोड़कर और varPortfel कर रहा है। अगर यह एक स्ट्रिंग आदि है?

उत्तर

10

MSDN प्रलेखन से:।

"इससे पहले कि आप तैयार कहते हैं, बयान में प्रत्येक पैरामीटर के डेटा प्रकार तैयार रहने की निर्दिष्ट प्रत्येक पैरामीटर चर लंबाई डेटा प्रकार है कि के लिए, आप अधिकतम आकार की जरूरत करने के लिए आकार संपत्ति सेट करना होगा। रिटर्न एक त्रुटि तैयार करता है, तो इन शर्तों को पूरा नहीं कर रहे हैं।

आपके बाद एक निष्पादित विधि को कॉल करते हैंबुला तैयार, किसी भी पैरामीटर मान मूल्य आकार संपत्ति द्वारा निर्दिष्ट से भी बड़ा है कि स्वचालित रूप से पैरामीटर का मूल निर्दिष्ट आकार, और कोई काट-छांट त्रुटियों लौटा दिया जाता है करने के लिए छोटा कर दिया है।

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

इसके अलावा," CommandType संपत्ति TableDirect पर सेट है, तैयार कुछ नहीं करता है। यदि कमांड टाइप स्टोर किए गए प्रसंस्करण पर सेट है, तो पर कॉल सफल होना चाहिए, ..."

सामान्य रूप में

यह सुनिश्चित करें कि अंत उपयोगकर्ता जानकारी जोड़ने या हटाने के लिए एक SQL इंजेक्शन तकनीक का उपयोग नहीं कर रहा है बनाने के लिए प्रयोग किया जाता है आप नहीं करते उन्हें भी डेटाबेस से चाहते हैं।

मैं इस पर देखा और इस आलेख को देखें http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.prepare.aspx. आपकी समस्या है कि आपको चलाने से पहले अपने पैरामीटर को परिभाषित करने की आवश्यकता है। .Prepare() और फिर चलाने के बाद अपने पैरामीटर सेट करें .repare()। अभी आप दोनों पहले कर रहे हैं। मैं इस तरह कुछ कोशिश करूंगा (नोट मैंने इसका परीक्षण नहीं किया है इसलिए मेरा वाक्यविन्यास थोड़ा सा हो सकता है)

public static decimal pobierzBenchmarkKolejny(string varPortfelID, DateTime data, decimal varBenchmarkPoprzedni, decimal varStopaOdniesienia) { 
    const string preparedCommand = @"SELECT [dbo].[ufn_BenchmarkKolejny](@varPortfelID, @data, @varBenchmarkPoprzedni, @varStopaOdniesienia) AS 'Benchmark'"; 
    using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) //if (varConnection != null) { 
    using (var sqlQuery = new SqlCommand(preparedCommand, varConnection)) { 

     sqlQuery.Parameters.Add("@varPortfelID"); 
     sqlQuery.Parameters.Add("@varStopaOdniesienia"); 
     sqlQuery.Parameters.Add("@data"); 
     sqlQuery.Parameters.Add("@varBenchmarkPoprzedni"); 

     sqlQuery.Prepare(); 
     sqlQuery.ExecuteNonQuery();//This might need to be ExecuteReader() 

     sqlQuery.Parameters[0].Value = varPortfelID; 
     sqlQuery.Parameters[1].Value = varStopaOdniesienia; 
     sqlQuery.Parameters[2].Value = data; 
     sqlQuery.Parameters[3].Value = varBenchmarkPoprzedni; 

     using (var sqlQueryResult = sqlQuery.ExecuteReader()) 
      if (sqlQueryResult != null) { 
       while (sqlQueryResult.Read()) { 

       } 
      } 
    } 
} 
+0

प्रदर्शन और अन्य चीजों के बारे में क्या? क्या यह केवल एसक्यूएल इंजेक्शन को रोकने के लिए है? मैंने इस प्रश्न पूछने से पहले एमएसडीएन दस्तावेज खुद पढ़ा है और उद्धृत हिस्सा मेरे सवालों के उपयोग के लिए वास्तव में उपयोगी नहीं है या नहीं और यदि उसके पास कुछ वेबसाइटों पर सुझाए गए प्रदर्शन लाभ हैं। – MadBoy

+0

मेरी समझ सब कुछ परिभाषित करके है कि यह क्वेरी योजना को कैश और पुन: उपयोग कर सकती है। मुझे लगता है कि यह आपको अत्यधिक लाभ नहीं देता है। –

+0

क्या मेरे पास कोड में उपयोग सही है? मैंने सभी पैरामीटर सेट किए जाने के बाद तैयार होने की कोशिश की और त्रुटि फेंक दी गई। तो क्या यह है कि sqlQuery.Prepare हमेशा पैरामीटर से पहले इस्तेमाल किया जाना चाहिए या? – MadBoy

6

अन्य लाभ यह है कि ऐसा करके SQL क्वेरी योजना संकलित की जाती है, कैश्ड और का पुन: उपयोग किया जाता है। यदि आपकी क्वेरी में कम मात्रा में कॉल के लिए यह कोई बड़ा सौदा नहीं है, लेकिन यदि आपके पास बहुत कुछ है तो वास्तव में ऐसा करने के लिए कुछ महत्वपूर्ण प्रदर्शन फायदे हैं।

+3

क्या आप कोई सहायक लिंक जोड़ सकते हैं? –

+0

एसक्यूएलएमएएमएंड ऑब्जेक्ट के साथ उपयोग किए गए एसक्यूएल पैरामीटर की वजह से योजना का पुन: उपयोग किया जाता है, क्योंकि .net एसक्यूएल कथन को sp_executesql प्रक्रिया में लपेट देगा जो एक पुन: प्रयोज्य योजना उत्पन्न करेगा। – Magier

4

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

तैयार किए गए आदेशों का उपयोग उस एप्लिकेशन की सफलता के लिए महत्वपूर्ण था, क्योंकि यह अकेले सिस्टम को वास्तव में उपयोग करने योग्य बना देता था।

दूसरे शब्दों में: यदि आप कई SQL कमांड निष्पादित करते हैं - जो पैरामीटर मानों में बिल्कुल समान या भिन्न होते हैं - तो आपको भारी प्रदर्शन बढ़ावा दिखाई देगा।

मेरे पास सटीक संख्या या लिंक नहीं हैं, लेकिन मैं अपने अनुभव को प्रमाणित कर सकता हूं।

+1

मैं पूरी तरह से विश्वास करता हूं कि आप क्या कह रहे हैं - लेकिन @OP: कृपया इसके विपरीत भी विचार करें। तैयार बयान वाले डीबी के आधार पर क्वेरी विश्लेषक को कठिन समय और गलत इंडेक्स चुनना पड़ सकता है। हमने देखा कि विशेष रूप से डीबी 2 पर कॉलम के साथ असमान मूल्य वितरण के साथ। इसलिए प्रत्येक प्रदर्शन सलाह के साथ: आपको इसे अपने परिदृश्य के लिए मापना होगा –

0

कई स्टैकओवरफ्लो का दावा है कि prepare विधि का उपयोग करते समय प्रदर्शन में सुधार होगा जब क्वेरी को सीवरल समय का पुन: उपयोग किया जाता है, इसलिए मैंने प्रदर्शन लाभ का मूल्यांकन करने के लिए एक बेंचमार्क लागू किया। नतीजा: बिल्कुल कोई सुधार नहीं हुआ!

मुझे यकीन है कि मैं अपने बेंचमार्क में कुछ भी याद आ रही नहीं किया गया था बनाने के लिए की जांच करने का फैसला किया है और मैं IDbCommand.Prepare Method documentation में इस टिप्पणी में आए:

सर्वर स्वचालित रूप से पुन: उपयोग के रूप में आवश्यक के लिए योजना कैश; इसलिए, इस विधि को सीधे अपने क्लाइंट एप्लिकेशन में कॉल करने की आवश्यकता नहीं है।

मैं भी इस Databases Administrators answer जो आप prepare विधि के बारे में जानकारी का एक बहुत कुछ दे पाया और कारण है कि मैं किसी भी महत्वपूर्ण सुधार नहीं मिला।

एसक्यूएल इंजेक्शन के बारे में, आप इसके खिलाफ संरक्षित होंगे क्योंकि आपने पैरामीटरयुक्त एसक्यूएल कॉमांड का उपयोग किया है ... नहीं क्योंकि आपने तैयार विधि कहा है।

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