Mysql
 sql >> डेटाबेस >  >> RDS >> Mysql

मैं एक व्युत्पन्न तालिका क्वेरी को और कैसे अनुकूलित कर सकता हूं जो जॉइन समकक्ष से बेहतर प्रदर्शन करती है?

खैर, मुझे एक समाधान मिला। इसमें बहुत सारे प्रयोग हुए, और मुझे लगता है कि यह एक अच्छी किस्मत है, लेकिन यहाँ यह है:

CREATE TABLE magic ENGINE=MEMORY
SELECT
  s.shop_id AS shop_id,
  s.id AS shift_id,
  st.dow AS dow,
  st.start AS start,
  st.end AS end,
  su.user_id AS manager_id
FROM shifts s
JOIN shift_times st ON s.id = st.shift_id
JOIN shifts_users su ON s.id = su.shift_id
JOIN shift_positions sp ON su.shift_position_id = sp.id AND sp.level = 1

ALTER TABLE magic ADD INDEX (shop_id, dow);

CREATE TABLE tickets_extra ENGINE=MyISAM
SELECT 
  t.id AS ticket_id,
  (
    SELECT m.manager_id
    FROM magic m
    WHERE DAYOFWEEK(t.created) = m.dow
    AND TIME(t.created) BETWEEN m.start AND m.end
    AND m.shop_id = t.shop_id
  ) AS manager_created,
  (
    SELECT m.manager_id
    FROM magic m
    WHERE DAYOFWEEK(t.resolved) = m.dow
    AND TIME(t.resolved) BETWEEN m.start AND m.end
    AND m.shop_id = t.shop_id
  ) AS manager_resolved
FROM tickets t;
DROP TABLE magic;

लंबी व्याख्या

अब, मैं समझाता हूं कि यह क्यों काम करता है, और मेरे रिश्तेदार हालांकि प्रक्रिया और यहां पहुंचने के लिए कदम उठाते हैं।

सबसे पहले, मुझे पता था कि मैं जिस क्वेरी का प्रयास कर रहा था वह विशाल व्युत्पन्न तालिका और इसके बाद के जॉइन के कारण पीड़ित थी। मैं अपनी अच्छी तरह से अनुक्रमित टिकट तालिका ले रहा था और उस पर सभी शिफ्ट_टाइम्स डेटा में शामिल हो रहा था, फिर MySQL को उस पर चबाने दे रहा था, जबकि यह शिफ्ट और शिफ्ट_पोजिशन टेबल में शामिल होने का प्रयास करता था। यह व्युत्पन्न बीहमोथ एक 2 मिलियन पंक्ति अनइंडेक्स्ड मेस तक होगा।

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

इसलिए, जैसा कि व्युत्पन्न तालिका "जाने का रास्ता" प्रतीत होता है, मैं कुछ समय के लिए हठपूर्वक इस पर कायम रहा। मैंने इसे जॉइन क्लॉज में डालने की कोशिश की, कोई सुधार नहीं। मैंने इसमें व्युत्पन्न तालिका के साथ एक अस्थायी तालिका बनाने की कोशिश की, लेकिन फिर से यह बहुत धीमी थी क्योंकि अस्थायी तालिका को अनइंडेक्स किया गया था।

मुझे एहसास हुआ कि मुझे शिफ्ट, समय, स्थिति की इस गणना को समझदारी से संभालना था। मैंने सोचा, शायद एक दृश्य जाने का रास्ता होगा। क्या होगा यदि मैंने एक ऐसा दृश्य बनाया है जिसमें यह जानकारी है:(shop_id, shift_id, dow, start, end, manager_id)। फिर, मुझे बस shop_id और संपूर्ण DAYOFWEEK/TIME गणना द्वारा टिकट तालिका में शामिल होना होगा, और मैं व्यवसाय में रहूंगा। बेशक, मैं यह याद रखने में असफल रहा कि MySQL दृश्य को आसानी से संभालता है। यह उन्हें बिल्कुल भी अमल में नहीं लाता है, यह केवल उस क्वेरी को चलाता है जिसका उपयोग आप अपने लिए दृश्य प्राप्त करने के लिए करते। तो इस पर टिकट शामिल करके, मैं अनिवार्य रूप से अपनी मूल क्वेरी चला रहा था - कोई सुधार नहीं।

इसलिए, एक दृश्य के बजाय मैंने एक अस्थायी तालिका का उपयोग करने का निर्णय लिया। यह अच्छी तरह से काम करता है अगर मैं एक समय में केवल एक प्रबंधक (बनाया या हल किया गया) प्राप्त करता हूं, लेकिन यह अभी भी बहुत धीमा था। साथ ही, मुझे पता चला कि MySQL के साथ आप एक ही क्वेरी में एक ही तालिका को दो बार संदर्भित नहीं कर सकते हैं (मुझे अपनी अस्थायी तालिका में दो बार शामिल होना होगा, ताकि मैं मैनेजर_क्रिएटेड और मैनेजर_रेसोल्व्ड के बीच अंतर कर सकूं)। यह एक बड़ा डब्ल्यूटीएफ है, क्योंकि मैं इसे तब तक कर सकता हूं जब तक मैं "अस्थायी" निर्दिष्ट नहीं करता - यह वह जगह है जहां तालिका बनाएं जादू इंजन =मेमोरी खेल में आया।

हाथ में इस छद्म अस्थायी तालिका के साथ, मैंने अपने जॉइन को सिर्फ मैनेजर_क्रिएटेड के लिए फिर से करने की कोशिश की। इसने अच्छा प्रदर्शन किया, लेकिन फिर भी धीमा। फिर भी, जब मैं एक ही प्रश्न में प्रबंधक_ समाधान प्राप्त करने के लिए फिर से शामिल हुआ तो क्वेरी समय समताप मंडल में वापस टिक गया। EXPLAIN को देखते हुए टिकटों का पूरा टेबल स्कैन (पंक्तियों ~ 2mln), जैसा कि अपेक्षित था, और जॉइन को जादू की मेज पर ~ 2,087 प्रत्येक पर दिखाया गया था। एक बार फिर, ऐसा लग रहा था कि मैं असफल हो रहा हूं।

अब मैं इस बारे में सोचने लगा कि जॉइन से पूरी तरह कैसे बचा जाए और तभी मुझे कुछ अस्पष्ट प्राचीन संदेश बोर्ड पोस्ट मिली, जहां किसी ने उप-चयनों का उपयोग करने का सुझाव दिया था (मेरे इतिहास में लिंक नहीं मिल रहा है)। यही कारण है कि ऊपर दिखाई गई दूसरी SELECT क्वेरी (टिकट_अतिरिक्त निर्माण एक) का कारण बनी। केवल एक प्रबंधक क्षेत्र का चयन करने के मामले में, इसने अच्छा प्रदर्शन किया, लेकिन फिर से दोनों के साथ यह बकवास था। मैंने EXPLAIN को देखा और यह देखा:

*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: t
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 173825
        Extra: 
*************************** 2. row ***************************
           id: 3
  select_type: DEPENDENT SUBQUERY
        table: m
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 2037
        Extra: Using where
*************************** 3. row ***************************
           id: 2
  select_type: DEPENDENT SUBQUERY
        table: m
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 2037
        Extra: Using where
3 rows in set (0.00 sec)

एके, खतरनाक डिपेंडेंट सबक्वायरी। अक्सर इनसे बचने का सुझाव दिया जाता है, क्योंकि MySQL आमतौर पर उन्हें बाहरी रूप से निष्पादित करेगा, बाहरी की प्रत्येक पंक्ति के लिए आंतरिक क्वेरी को निष्पादित करेगा। मैंने इसे नज़रअंदाज़ किया, और सोचा:"अच्छा... क्या हुआ अगर मैंने अभी इस बेवकूफ जादू की मेज को अनुक्रमित किया?"। इस प्रकार, ADD अनुक्रमणिका (shop_id, dow) का जन्म हुआ।

इसे देखें:

mysql> CREATE TABLE magic ENGINE=MEMORY
<snip>
Query OK, 3220 rows affected (0.40 sec)

mysql> ALTER TABLE magic ADD INDEX (shop_id, dow);
Query OK, 3220 rows affected (0.02 sec)

mysql> CREATE TABLE tickets_extra ENGINE=MyISAM
<snip>
Query OK, 1933769 rows affected (24.18 sec)

mysql> drop table magic;
Query OK, 0 rows affected (0.00 sec)

अब वह मैं किस बारे में बात कर रहा हूँ!

निष्कर्ष

यह निश्चित रूप से पहली बार है जब मैंने फ्लाई पर एक गैर-अस्थायी तालिका बनाई है, और इसे फ्लाई पर इंडेक्स किया है, बस एक ही क्वेरी को कुशलतापूर्वक करने के लिए। मुझे लगता है कि मैंने हमेशा माना है कि फ्लाई पर एक इंडेक्स जोड़ना एक बेहद महंगा ऑपरेशन है। (2mln पंक्तियों की मेरी टिकट तालिका पर एक अनुक्रमणिका जोड़ने में एक घंटे से अधिक समय लग सकता है)। फिर भी, मात्र 3,000 पंक्तियों के लिए यह एक आसान कदम है।

DEPENDENT SUBQUERIES से डरो मत, अस्थायी तालिकाएँ बनाना जो वास्तव में नहीं हैं, मक्खी, या एलियंस पर अनुक्रमणित करना। वे सभी सही स्थिति में अच्छी चीजें हो सकते हैं।

स्टैक ओवरफ्लो की सभी मदद के लिए धन्यवाद। :-डी



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL अद्यतन और प्रतिस्थापन बदलें

  2. टेबल बनाते समय Django MySQL त्रुटि

  3. MYSQL में दूसरा MAXIMUM DATE कैसे प्राप्त करें?

  4. असफल प्रविष्टियों पर MySQL ऑटोइनक्रिकमेंट क्यों बढ़ता है?

  5. MySQL योग, समूह द्वारा गिनें और शामिल हों