2012-09-26 16 views
12

हमारी टीम ने पिछले हफ्ते डीबगिंग और कई MySQL लॉक टाइमआउट्स और कई अत्यंत लंबे समय तक चलने वाले प्रश्नों के स्रोत को खोजने का प्रयास किया। अंत में ऐसा प्रतीत होता है कि यह प्रश्न अपराधी है।यह क्वेरी लॉक प्रतीक्षा टाइमआउट क्यों करती है?

mysql> explain 

SELECT categories.name AS cat_name, 
COUNT(distinct items.id) AS category_count 
FROM `items` 
INNER JOIN `categories` ON `categories`.`id` = `items`.`category_id` 
WHERE `items`.`state` IN ('listed', 'reserved') 
    AND (items.category_id IS NOT NULL) 
GROUP BY categories.name 
ORDER BY category_count DESC 
LIMIT 10\G 

*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: items 
     type: range 
possible_keys: index_items_on_category_id,index_items_on_state 
      key: index_items_on_category_id 
     key_len: 5 
      ref: NULL 
     rows: 119371 
     Extra: Using where; Using temporary; Using filesort 
*************************** 2. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: categories 
     type: eq_ref 
possible_keys: PRIMARY 
      key: PRIMARY 
     key_len: 4 
      ref: production_db.items.category_id 
     rows: 1 
     Extra: 
2 rows in set (0.00 sec) 

मैं देख सकता हूं कि यह एक बुरा टेबल स्कैन कर रहा है और चलाने के लिए एक अस्थायी तालिका बना रहा है।

यह प्रश्न दस दिनों के कारक और कुछ प्रश्नों के कारण डेटाबेस प्रतिक्रिया प्रतिक्रिया का कारण क्यों बनता है जो आम तौर पर 40,000 एमएस और उच्चतर समय में विस्फोट करने के लिए 40-50ms (आइटम टेबल पर अपडेट) लेते हैं?

+1

क्या आपने * बिना * 'विशिष्ट 'प्रोफाइलिंग करने का प्रयास किया था? ऐसा करने में काफी काम होता है और आपके पास फ़िल्टर करने के लिए बहुत कम पंक्तियां हैं :) – PhD

+0

बहुत अच्छा। नहीं, ऐसा नहीं किया। यह निश्चित रूप से इसे अनुकूलित करने में मदद करता है। अभी भी इस बात पर स्पष्ट नहीं है कि इस तरह की धीमी क्वेरी क्यों हमारे लिए इतनी सारी समस्याएं पैदा कर सकती है। – chrishomer

+0

बस सोच रहा है कि आपको इसकी आवश्यकता क्यों है और (आइटम.category_id पूर्ण नहीं है) '- क्योंकि यह एक' इनर जॉइन 'है - श्रेणी.आईडी को 'NULL' –

उत्तर

5

कि एक सौदे के अंदर चल रहा है की तरह

  1. अधिक जानकारी के बिना बताना मुश्किल है?
  2. यदि हां, तो अलगाव स्तर क्या है?
  3. कितने श्रेणियां हैं?
  4. कितने आइटम?

मेरा अनुमान होगा कि क्वेरी बहुत धीमी है और एक लेन-देन के अंदर अपनी चल रहा है (जो यह शायद जब से तुम इस समस्या है) और है आइटम मेज पर रेंज-ताले शायद जारी करने के जो नहीं कर सकते आगे बढ़ने के लिए लिखते हैं ताकि अपडेट को धीमा कर दिया जाए जब तक कि वे तालिका पर लॉक प्राप्त नहीं कर लेते।

और मैं मैं क्या आपकी क्वेरी और कार्य योजना लागू करके से देख सकते हैं के आधार पर टिप्पणियों के एक जोड़े हैं: बजाय होने का,

1) आपका items.state शायद एक सूची के रूप में बेहतर होगा वस्तुओं में प्रत्येक पंक्ति पर स्ट्रिंग, यह अंतरिक्ष दक्षता के लिए है और आईडी की तुलना स्ट्रिंग की तुलना करने की तुलना में तेज़ है (चाहे इंजन जो भी अनुकूलन कर सकता हो)।

2) मैं अनुमान लगा रहा हूँ items.state कम प्रमुखता (कुछ अनन्य मानों के साथ एक स्तंभ) है, इसलिए उस कॉलम में एक सूचकांक शायद आप की मदद करने से ज्यादा नुकसान हो रहा है। इंडेक्स को संयोजित करने के बाद पंक्तियों को डालने/हटाने/अपडेट करने पर प्रत्येक इंडेक्स सिर पर जोड़ता है, इस विशेष इंडेक्स का उपयोग संभवतः सार्थक नहीं किया जाता है। बेशक, मैं अनुमान लगा रहा हूं, यह शेष प्रश्नों पर निर्भर करता है।

SELECT 
    ; Grouping by name, means comparing strings. 
    categories.name AS cat_name, 
    ; No need for distinct, the same item.id cannot belong to different categories 
    COUNT(distinct items.id) AS category_count 
FROM `items` 
INNER JOIN `categories` ON `categories`.`id` = `items`.`category_id` 
WHERE `items`.`state` IN ('listed', 'reserved') 
    ; Not needed, the inner join gets rid of items with no category_id 
    AND (items.category_id IS NOT NULL) 
GROUP BY categories.name 
ORDER BY category_count DESC 
LIMIT 10\G 

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

मैं जैसी क्वेरी लिखते थे:

SELECT categories.name, counts.n 
FROM (SELECT category_id, COUNT(id) n 
     FROM items 
     WHERE state IN ('listed', 'reserved') AND category_id is not null 
     GROUP BY category_id ORDER BY COUNT(id) DESC LIMIT 10) counts 
JOIN categories on counts.category_id = categories.id 
ORDER BY counts.n desc   

(मैं माफी चाहता हूँ अगर वाक्य रचना सही मैं MySQL रोक नहीं है)

इस क्वेरी क्या इंजन शायद कर देगा के साथ:

आइटम का उपयोग करें।'इंडेक्स', 'आरक्षित' आइटम और श्रेणी_आईडी की तुलना में श्रेणी_आईडी द्वारा समूह को प्राप्त करने के लिए राज्य सूचकांक, तारों को केवल 10 शीर्षतम गणना प्राप्त करने के बाद, नाम प्राप्त करने के लिए श्रेणियों के साथ शामिल हों (लेकिन केवल 10 अनुक्रमणिका का उपयोग करके)।

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