2012-10-13 37 views
7

हमारे पास एक ऐसा एप्लिकेशन है जो एमएफसी (वीएस -2010) में सीडीएबेस/सीआरकॉर्डसेट के माध्यम से ओडीबीसी का उपयोग करता है। हमारे पास दो बैकएंड लागू हैं। एमएसएसक्यूएल और माईएसक्यूएल।एसक्यूएल मूल क्लाइंट 10 प्रदर्शन दुखी (सर्वर-साइड कर्सर के कारण)

अब, जब हम एमएसएसक्यूएल (मूल क्लाइंट 10.0 के साथ) का उपयोग करते हैं, तो चयन के साथ रिकॉर्ड्स पुनर्प्राप्त धीमी लिंक (उदाहरण के लिए वीपीएन) के माध्यम से नाटकीय रूप से धीमा है। MySQL ओडीबीसी ड्राइवर इस बुरा व्यवहार का प्रदर्शन नहीं करता है।

उदाहरण के लिए:

CRecordset r(&m_db); 
r.Open(CRecordset::snapshot, L"SELECT a.something, b.sthelse FROM TableA AS a LEFT JOIN TableB AS b ON a.ID=b.Ref"); 
r.MoveFirst(); 
while(!r.IsEOF()) 
{ 
    // Retrieve 
    CString strData; 
    crs.GetFieldValue(L"a.something", strData); 
    crs.MoveNext(); 
} 

अब, MySQL ड्राइवर के साथ, सब कुछ एकदम सही ढंग से चलाता है। क्वेरी वापस आ गई है, और सब कुछ बिजली तेज है। हालांकि, एमएसएसक्यूएल मूल क्लाइंट के साथ, चीजें धीमी हो जाती हैं, क्योंकि प्रत्येक MoveNext() पर, ड्राइवर सर्वर के साथ संचार करता है।

मुझे लगता है कि यह सर्वर-साइड कर्सर के कारण है, लेकिन मुझे उन्हें अक्षम करने का कोई तरीका नहीं मिला। मैंने इसका उपयोग करने का प्रयास किया है:

::SQLSetConnectAttr(m_db.m_hdbc, SQL_ATTR_ODBC_CURSORS, SQL_CUR_USE_ODBC, SQL_IS_INTEGER); 

लेकिन इससे कोई मदद नहीं मिली। एसक्यूएल प्रोफाइलर में sp_cursorfetch() et al के लिए अभी भी लंबे समय से चलने वाले निष्पादन हैं। मैंने स्क्लाप्पी और थोक fetch के साथ एक छोटी संदर्भ परियोजना भी कोशिश की है, लेकिन यह लंबे समय तक FetchNext() में भी लटकता है (भले ही परिणाम में केवल एक रिकॉर्ड है)। हालांकि यह केवल बाएं जॉइन, टेबल-मूल्यवान फ़ंक्शंस आदि के साथ प्रश्नों पर होता है ध्यान दें कि क्वेरी उस लंबे नहीं लेती है - एक ही समय में SQL स्टूडियो के माध्यम से एक ही SQL को एक ही कनेक्शन पर उचित कनेक्शन में लौटाता है।

Question1: है के रूप में MySQL चालक यह करने के लिए लगता है किसी भी तरह इसी तरह से स्थानीय स्तर पर उपयोग स्थानीय कर्सर को "कैश" सभी परिणाम मूल क्लाइंट प्राप्त करने के लिए संभव है?

शायद यह गलत दृष्टिकोण है, लेकिन मुझे यकीन नहीं है कि यह और कैसे करें।

हम चाहते हैं कि सभी डेटा एक बार से एक बार से पुनर्प्राप्त करें, फिर अगली क्वेरी तक सर्वर से कभी बात न करें। हमें रिकॉर्डसेट अपडेट, डिलीट इत्यादि या उस बकवास में से कोई भी परवाह नहीं है। हम केवल डेटा पुनर्प्राप्त करना चाहते हैं। हम उस रिकॉर्डसेट को लेते हैं, सभी डेटा प्राप्त करते हैं, और इसे हटाते हैं।

प्रश्न 2: क्या ओडीबीसी के साथ एमएफसी में डेटा पुनर्प्राप्त करने का एक और अधिक प्रभावी तरीका है?

+1

MySQL ड्राइवर निश्चित रूप से क्लाइंट पर परिणाम सेट कैश नहीं करता है। वह गहराई से बेकार होगा। – usr

+0

एमएचएच शायद मैं थोड़ा सा गलतफहमी कर दिया। मुझे लगता है कि MySQL ड्राइवर एक ही समय में सभी रिकॉर्ड लाता है और डेटा पर स्थानीय कर्सर का उपयोग करता है। – namezero

उत्तर

3

मैं थोड़ा और अधिक के लिए समस्या के साथ tinkered और पाया है इन दो लिंक:

MSDN Link

MSDN Blog

पहले लिंक में, यह वर्णन करता है कि सर्वर साइड कर्सर द्वारा किया जाता है मूल क्लाइंट 10 केवल तभी जब डिफ़ॉल्ट विकल्प बदल दिए जाते हैं:

जब ये विकल्प उनके डिफ़ॉल्ट पर सेट होते हैं उस समय एक SQL कथन निष्पादित किया जाता है, SQL सर्वर मूल क्लाइंट ODBC ड्राइवर परिणाम सेट को लागू करने के लिए सर्वर कर्सर का उपयोग नहीं करता है; इसके बजाय, यह एक डिफ़ॉल्ट परिणाम सेट का उपयोग करता है।

लिंक 2 एक ब्लॉग है, जो एक एसक्यूएल देव ब्लॉग है, यह कहना है कि यह:

यह पता चला कि डेवलपर को स्पष्ट रूप से एक सर्वर कर्सर लिए नहीं कहा था। लेकिन जब उन्होंने साइड इफेक्ट के रूप में ब्लॉक लाने के लिए, SQL सर्वर ओडीबीसी ड्राइवर ने सर्वर कर्सर के लिए पूछा ... यह अप्रत्याशित है!

हाँ, निश्चित रूप से है कि अप्रत्याशित है ...

मैं ब्लॉक एक सर्वर कर्सर एक डिफ़ॉल्ट परिणाम (आग नली कर्सर) सेट के बजाय से अधिक को हासिल करेगा कैसे कर सकता है?

अब, समाधान के कार्यान्वयन यह है:

के बजाय:

// crs is a CRecordSet 
crs.Open(CRecordset::snapshot, L"SELECT something..."); 

यह करें:

// crs is a CRecordSet 
crs.Open(CRecordset::forwardOnly, L"SELECT something..."); 

यह सरल परिवर्तन एक के निर्माण के ट्रिगर नहीं करेगा सर्वर-साइड कर्सर, और MySQL ड्राइवर के व्यवहार की नकल करता है।

while(crs.MoveNext()) nCount++; 

कौन सा वैसे भी एक बुरा विचार है:

नुकसान यह है कि अब आप (माइक्रोसॉफ्ट अनुशंसित) जिस तरह के माध्यम से पंक्ति संख्या प्राप्त नहीं कर सकता है। इसके अलावा, एक :: SQLGetRowCount() अब हर समय काम नहीं करेगा।

मैं इस तरह कि इस मुद्दे (यह किसी भी एएनएसआई-संगत एसक्यूएल स्रोत पर काम करना चाहिए) समाधान कर लिया है:

//strQuery is the random query passed to CountRows() 
std::wstringstream ssQuery; 
ssQuery << L"SELECT COUNT(*) AS Count FROM (" << strQuery << L") AS t"; 
CRecordset crs(&m_Database); 
crs.Open(CRecordset::forwardOnly, ssQuery.str().c_str()); 
// Now retrieve the only "Count" field from the recordset. 

मुझे आशा है कि यह भविष्य में किसी और में मदद करता है।

+0

मैं इसे गिनती पंक्तियों के लिए काम करना चाहता हूं, आपको चयन से ऑर्डर को फ़िल्टर करना होगा। – namezero