2010-10-01 14 views
7

मैं एक गोदाम मेज है कि इस तरह दिखता है: एक के लिएअतिरिक्त स्तंभ खंडहर MySQL प्रदर्शन

CREATE TABLE Warehouse (
    id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, 
    eventId BIGINT(20) UNSIGNED NOT NULL, 
    groupId BIGINT(20) NOT NULL, 
    activityId BIGINT(20) UNSIGNED NOT NULL, 
    ... many more ids, 
    "txtProperty1" VARCHAR(255), 
    "txtProperty2" VARCHAR(255), 
    "txtProperty3" VARCHAR(255), 
    "txtProperty4" VARCHAR(255), 
    "txtProperty5" VARCHAR(255), 
    ... many more of these 
    PRIMARY KEY ("id") 
    KEY "WInvestmentDetail_idx01" ("groupId"), 
    ... several more indices 
) ENGINE=INNODB; 

अब, निम्न क्वेरी 0.8s के बारे में क्वेरी समय और 0.2s में में खर्च करता है समय लाने, लगभग एक सेकंड की कुल। क्वेरी ~ 67,000 पंक्तियां लौटाती है।

SELECT eventId 
FROM Warehouse 
WHERE accountId IN (10, 8, 13, 9, 7, 6, 12, 11) 
    AND scenarioId IS NULL 
    AND insertDate BETWEEN DATE '2002-01-01' AND DATE '2011-12-31' 
ORDER BY insertDate; 

चुनिंदा खंड में अधिक आईडी जोड़ना वास्तव में प्रदर्शन को बिल्कुल नहीं बदलता है।

SELECT eventId, groupId, activityId, insertDate 
FROM Warehouse 
WHERE accountId IN (10, 8, 13, 9, 7, 6, 12, 11) 
    AND scenarioId IS NULL 
    AND insertDate BETWEEN DATE '2002-01-01' AND DATE '2011-12-31' 
ORDER BY insertDate; 

हालांकि, "संपत्ति" कॉलम जोड़ने से यह 0.6s समय और 1.8 प्रश्न पूछताछ में बदल जाता है।

SELECT eventId, txtProperty1 
FROM Warehouse 
WHERE accountId IN (10, 8, 13, 9, 7, 6, 12, 11) 
    AND scenarioId IS NULL 
    AND insertDate BETWEEN DATE '2002-01-01' AND DATE '2011-12-31' 
ORDER BY insertDate; 

अब वास्तव में अपने मोजे बंद करने के लिए। txtProperty1 के बजाय, txtProperty2 का उपयोग करते समय 0.8s लाने के लिए समय बदलता है, 24s क्वेरी!

SELECT eventId, txtProperty2 
FROM Warehouse 
WHERE accountId IN (10, 8, 13, 9, 7, 6, 12, 11) 
    AND scenarioId IS NULL 
    AND insertDate BETWEEN DATE '2002-01-01' AND DATE '2011-12-31' 
ORDER BY insertDate; 

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

यह वास्तव में मेरे लिए रहस्यमय है। मैं देख सकता हूं कि चुनिंदा खंड में कॉलम जोड़ने से केवल थोड़ी देर में वृद्धि हो सकती है, लेकिन इसे क्वेरी समय नहीं बदलना चाहिए, खासकर महत्वपूर्ण नहीं। इस मंदी के कारण होने के कारण मैं किसी भी विचार की सराहना करता हूं।

संपादित करें - अधिक डेटा बिंदुओं

चुनें * वास्तव में txtProperty2 से बेहतर साबित - 0.8s क्वेरी, 8.4s लाने। बहुत बुरा मैं इसका उपयोग नहीं कर सकता क्योंकि fetch time (अपेक्षित) बहुत लंबा है।

+0

इन समय कितने दोहराने योग्य थे? –

+2

और न ही अनुक्रमित किया गया है (ऐसा नहीं है कि इससे कोई फर्क पड़ता है) .... यह हो सकता है (http://en.wikipedia.org/wiki/Index_%28database%29#Covering_Index) –

+0

@ रोवलैंड - हाँ, मेरे पास है दो देव लैपटॉप और एक क्यूए सर्वर पर समय दोहराया। जाहिर है, सर्वर तेज है, लेकिन पैटर्न बनी हुई है। –

उत्तर

0

मैं स्वीकार करूंगा कि यह एक अनुमान है, लेकिन मैं इसे एक शॉट दूंगा।

आपके पास id - पहला क्षेत्र - प्राथमिक कुंजी के रूप में है। मुझे 100% यकीन नहीं है कि MySQL क्लस्टर इंडेक्स को लुकअप के रूप में कैसे करता है, लेकिन यह संदेह करना उचित है कि, किसी दिए गए आईडी के लिए, उस आईडी के साथ रिकॉर्ड के लिए कुछ "सूचक" है।

फ़ील्ड की शुरुआत को ढूंढना अपेक्षाकृत आसान है जब सभी पूर्व फ़ील्ड चौड़ाई तय कर चुके हैं। आपके सभी BIGINT(20) फ़ील्ड में एक परिभाषित आकार है जो डीबी इंजन को रिकार्ड की शुरुआत में पॉइंटर दिए गए फ़ील्ड को ढूंढना आसान बनाता है; यह एक साधारण गणना है। इसी प्रकार, पहले VARCHAR(255) फ़ील्ड की शुरुआत ढूंढना आसान है। उसके बाद, हालांकि, फ़ील्ड VARCHAR फ़ील्ड हैं, डीबी इंजन को अगले फ़ील्ड की शुरुआत को खोजने के लिए डेटा को ध्यान में रखना चाहिए, जो कि उस क्षेत्र की गणना करने की तुलना में बहुत धीमी है। तो, txtProperty1 के बाद किसी भी फ़ील्ड के लिए, आपको यह समस्या होगी।

क्या होगा यदि आपने सभी VARCHAR(255) फ़ील्ड्स को CHAR(255) फ़ील्ड में बदल दिया? यह बहुत संभव है कि आपकी क्वेरी वास्तव में मौजूद डेटा के बावजूद प्रत्येक CHAR(255) फ़ील्ड के लिए अधिकतम संग्रहण का उपयोग करने की लागत पर बहुत तेज होगी।

+0

क्षमा करें, कोई पासा नहीं। CHAR (255) में पहली 5 गुणों को बदलना वास्तव में 98s क्वेरी में क्वेरी चलाता है, 1.5s fetch। हालांकि, इस क्षेत्र में परीक्षण ने मुझे एक और अजीब खोज के लिए नेतृत्व किया है: txtProperty8 पर चयन करना उसी दंड के रूप में है txtProperty1 (केवल 2 सेकंड)। txtProperty7 कहीं (लगभग 5 सेकंड) के बीच में है। यह पूरी बात बहुत ही अजीब है। –

0

फ्रैगमेंटेड टेबलस्पेस?बदल एक अशक्त प्रयास करें तालिका:

ALTER TABLE tbl_name ENGINE=INNODB 
+0

क्षमा करें .. यह काम नहीं करता है। क्या यह इनोडीबीबी में अनुकूलन के समान ही काम करता है? –

+0

मुझे ऐसा नहीं लगता। फिर भी लगता है कि लगभग समान कॉलम के बीच नाटकीय मतभेदों को समझाने के लिए कुछ प्रकार की टेबलस्पेस त्रुटि हो सकती है। – igelkott

1

InnoDB इंजन के लिए MySQL documentation पता चलता है कि अगर आपके varchar डेटा पृष्ठ पर फिट नहीं करता है (यानी बी-वृक्ष संरचना के नोड), तो जानकारी होगी अतिप्रवाह पृष्ठों पर संदर्भित। तो आपकी विस्तृत वेयरहाउस तालिका पर, यह हो सकता है कि txtProperty1 ऑन-पेज है और txtProperty2 ऑफ़-पेज है, इस प्रकार पुनर्प्राप्त करने के लिए अतिरिक्त I/O की आवश्यकता है।

भी सुनिश्चित करें कि SELECT * बेहतर क्यों है; यह डिस्क के चारों ओर अपना रास्ता चुनने के बजाय अनुक्रमिक रूप से डेटा पढ़ने का लाभ ले सकता है।

+0

यह परिदृश्य पूरी तरह से संभव है एन मेरा डेटा। मैं 2s -> 24s पर पुनर्प्राप्ति समय में थोड़ा आश्चर्यचकित हूं, हालांकि। कोई प्रश्न है कि मैं क्वेरी समय को कैसे सुधार सकता हूं? –

+0

मेरे पास इसका कोई व्यावहारिक अनुभव नहीं है: पृष्ठ पर अधिक डेटा प्राप्त करने के 2 संभावित तरीके दिखाई देते हैं। ए) आप पृष्ठ को व्यापक बनाने का प्रयास कर सकते हैं: KEY_BLOCK_SIZE, या b सेट करके) क्या आपके पास डेटाटाइप आकारों के आसपास कोई लचीलापन है, उदा। क्या आपको बिगिनट होने के लिए संख्याओं की आवश्यकता है (एक हस्ताक्षरित आईएनटी या मेडिमिनट करेगा?), और/या VARCHARs केवल 100 लंबाई हो सकता है? – richaux

+0

ऐसा लगता है कि 'दिखाएं तालिका स्थिति' आपको वर्तमान 'KEY_BLOCK_SIZE' दिखाएगी। वह मूल्य क्या है? और txtProperty1 तक कॉलम आकारों को क्या जोड़ना है? –

0

चूंकि मैं एक SQL सर्वर उपयोगकर्ता हूं और MySQL लड़का नहीं हूं, यह एक लंबा शॉट है। SQL सर्वर में क्लस्टर सूचकांक तालिका है। सभी तालिका डेटा क्लस्टर सूचकांक में संग्रहीत किया जाता है। अतिरिक्त इंडेक्स उचित क्रम क्रम में क्रमबद्ध अनुक्रमित डेटा की अनावश्यक प्रतियों को स्टोर करते हैं।

मेरा तर्क यह है। जैसे ही आप क्वेरी में अधिक से अधिक डेटा जोड़ते हैं, वही समय नगण्य रहता है। मुझे लगता है कि ऐसा इसलिए है क्योंकि आप क्वेरी चरण के दौरान क्लस्टर इंडेक्स से सभी डेटा ला रहे हैं और fetch चरण के दौरान प्रभावी ढंग से कुछ भी नहीं बचा है।

चयन * जिस तरह से करता है वह काम करता है क्योंकि आपकी तालिका इतनी व्यापक है। जब तक आप केवल कुंजी और एक या दो अतिरिक्त कॉलम का अनुरोध कर रहे हों, तब तक क्वेरी के दौरान सबकुछ प्राप्त करना सबसे अच्छा है। एक बार जब आप सब कुछ मांगते हैं, तो दो चरणों के बीच लाने के लिए सस्ता हो जाता है। मैं अनुमान लगा रहा हूं कि यदि आप एक समय में अपनी क्वेरी में कॉलम जोड़ते हैं, तो आप उस सीमा को खोज लेंगे जहां क्वेरी विश्लेषक क्वेरी चरण में सभी fetching करने से स्विच करता है ताकि fetching चरण में अधिकांश fetching कर सकें।

+0

यह कुछ अन्य लोगों द्वारा वर्णित "कवर इंडेक्स" तकनीक की तरह लगता है। क्या यह अभी भी मामला है यदि न तो txtProperty1 और न ही txtProperty2 किसी भी इंडेक्स का हिस्सा हैं? –

0

आपको दो प्रश्नों की व्याख्या योजना पोस्ट करनी चाहिए ताकि हम देख सकें कि वे क्या हैं।

मेरा अनुमान है कि तेज़ व्यक्ति "कवरिंग इंडेक्स" का उपयोग कर रहा है, और धीमा कोई नहीं है।

इसका मतलब है कि धीमी गति से 67,000 प्राथमिक कुंजी लुकअप करना चाहिए, जो तालिका में सभी स्मृति में नहीं है (आमतौर पर 67k आईओ ऑपरेशंस की आवश्यकता होती है यदि तालिका मनमाने ढंग से बड़ी होती है और प्रत्येक पंक्ति अपने पृष्ठ पर होती है)।

MySQL में, एक्सप्लाइन एक सूचकांक का उपयोग किया जा रहा है, तो "सूचकांक का उपयोग" दिखाएगा।

+0

व्याख्या दोनों मामलों में समान है। भले ही खंड जहां वस्तुओं को अनुक्रमित किया गया हो, MySQL दोनों मामलों में एक पूर्ण तालिका स्कैन करने का निर्णय ले रहा है (संभवतः क्योंकि 67000 संपूर्ण तालिका के आकार का एक महत्वपूर्ण अंश दर्शाता है)। मैंने पिछले दो प्रश्नों में उल्लेख किया है, न तो "कवर इंडेक्स" तकनीक का उपयोग कर सकते हैं क्योंकि उनमें दोनों कॉलम हैं जो अनुक्रमित नहीं हैं। –

0

मुझे एक समान समस्या थी और अतिरिक्त सही आकार के इंडेक्स बनाने में काफी मदद मिली। विभाजित डेटाबेस टेबल का उपयोग करके और डेटाबेस रैम को ट्यून करने में भी मदद करता है।

अर्थात (eventID, txtProperty2)

नोट के लिए मेज पर एक सूचकांक जोड़ें: मैंने देखा है कि आप "वेयरहाउस" कहा गया है। ध्यान रखें कि यह कुछ हद तक उम्मीद है कि यदि आपके पास एक विशाल डेटाबेस तालिका है तो आप अतिरिक्त देरी के साथ काम कर रहे हैं, प्रत्येक बढ़ी हुई स्थिति के साथ उम्मीद की जाती है।

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