MySQL के साथ STRAIGHT_JOIN का उपयोग कब करें


88

मेरे पास बस एक काफी जटिल क्वेरी थी जिसके साथ मैं काम कर रहा था और इसे चलाने में 8 सेकंड लग रहे थे। EXPLAIN एक अजीब तालिका आदेश दिखा रहा था और मेरे सूचकांक सभी का उपयोग फॉरेक्स इंडेक्स संकेत के साथ भी नहीं किया जा रहा था। मैं STRAIGHT_JOIN कीवर्ड से जुड़ गया और अपने कुछ INNER JOIN कीवर्ड को बदलना शुरू कर दिया। मैंने काफी गति सुधार पर ध्यान दिया। आखिरकार मैंने इस क्वेरी के लिए अपने सभी INNER JOIN कीवर्ड को STRAIGHT_JOIN से बदल दिया और अब यह .01 सेकंड में चलता है।

मेरा प्रश्न यह है कि आप STRAIGHT_JOIN का उपयोग कब करते हैं और INNER JOIN का उपयोग कब करते हैं? यदि आप अच्छा प्रश्न लिख रहे हैं तो STRAIGHT_JOIN का उपयोग न करने का कोई कारण है?

जवाबों:


73

मैं एक अच्छे कारण के बिना STRAIGHT_JOIN का उपयोग करने की सलाह नहीं दूंगा। मेरा अपना अनुभव है कि MySQL क्वेरी ऑप्टिमाइज़र एक खराब क्वेरी योजना चुनता है जो मैं चाहूंगा, लेकिन अक्सर ऐसा नहीं होता है कि आपको इसे सामान्य रूप से बायपास करना चाहिए, जो कि यदि आप हमेशा STRAIGHT_JOIN का उपयोग करते हैं तो आप क्या करेंगे।

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

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


59
यह उत्तर वास्तव में नहीं समझाता है कि कब उपयोग करना है straight_join
पचेरियर

23

से MySQL संदर्भ में शामिल हों :

"STRAIGHT_JOIN, JOIN के समान है, सिवाय इसके कि बाएं टेबल को हमेशा दाईं टेबल से पहले पढ़ा जाता है। इसका उपयोग उन (कुछ) मामलों के लिए किया जा सकता है, जिनके लिए ज्वाइन ऑप्टिमाइज़र गलत क्रम में टेबल डालता है।"


27
धन्यवाद, लेकिन मैंने पहले ही इस पर MySQL मैनुअल पढ़ा। कुछ और स्पष्टीकरण की उम्मीद है।
ग्रेग

20

यहाँ एक परिदृश्य है जो अभी हाल ही में काम पर आया था।

तीन तालिकाओं पर विचार करें, ए, बी, सी।

ए में 3,000 पंक्तियाँ हैं; बी में 300,000,000 पंक्तियाँ हैं; और C की 2,000 पंक्तियाँ हैं।

विदेशी कुंजियों को परिभाषित किया गया है: बी (a_id), B (c_id)।

मान लीजिए कि आपके पास एक क्वेरी है जो इस तरह दिखती है:

select a.id, c.id
from a
join b on b.a_id = a.id
join c on c.id = b.c_id

मेरे अनुभव में, MySQL इस मामले में C -> B -> A जाना चुन सकता है। C, A और B से छोटा है, और वे सभी समान हैं।

परेशानी यह है कि MySQL आवश्यक रूप से (C.id और B.c_id) बनाम (A.id और B.a_id) के बीच के चौराहे के आकार को ध्यान में नहीं रखता है। यदि B और C के बीच जुड़ने से B जितनी पंक्तियाँ वापस आती हैं, तो यह बहुत खराब विकल्प है; यदि A से शुरू करने से B को A के रूप में कई पंक्तियों तक फ़िल्टर किया जाता, तो यह एक बेहतर विकल्प होता। straight_joinइस आदेश को इस तरह लागू करने के लिए इस्तेमाल किया जा सकता है:

select a.id, c.id
from a
straight_join b on b.a_id = a.id
join c on c.id = b.c_id

अब aइससे पहले ज्वाइन करना होगा b

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

यह आँकड़े पर निर्भर है। यदि डेटा वितरण बदलता है, तो गणना बदल सकती है। यह भी शामिल तंत्र के कार्यान्वयन के विवरण पर निर्भर है।

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


समस्या को ठीक करने के लिए आप सीधे जुड़ने का उपयोग कैसे करेंगे?
हनीले

@Hannele straight_joinदाएं से पहले बाईं तालिका का मूल्यांकन करती है। इसलिए यदि आप A -> B -> Cमेरे उदाहरण से जाना चाहते हैं , तो पहले joinकीवर्ड को बदल दिया जा सकता है straight_join
बैरी केली

आह साफ। इसे अपने उत्तर में एक उदाहरण के रूप में शामिल करना उपयोगी होगा :)
हैनले

18

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


11

STRAIGHT_JOIN, इस क्लॉज का उपयोग करके, आप JOINऑर्डर को नियंत्रित कर सकते हैं : कौन सा टेबल बाहरी लूप में स्कैन किया गया है और कौन सा आंतरिक लूप में है।


बाहरी लूप और इनर लूप क्या हैं?
इस्तियाक अहमद

@IstiaqueAhmed टेबल नेस्टेड लूप्स से जुड़ते हैं (टेबल ए से पहली पंक्ति लेते हैं और लूप थ्रो टेबल बी फिर दूसरी पंक्ति लेते हैं ... और इसी तरह। यहां टेबल ए बाहरी लूप में है)
लेखाकार م

6

मैं आपको बताऊंगा कि मुझे STRAIGHT_JOIN का उपयोग क्यों करना पड़ा:

  • मेरे पास एक क्वेरी के साथ एक प्रदर्शन मुद्दा था ।
  • क्वेरी को सरल करते हुए, क्वेरी अचानक अधिक कुशल थी
  • यह पता लगाने की कोशिश की जा रही है कि कौन सा विशिष्ट हिस्सा समस्या ला रहा है, मैं अभी नहीं कर सका। (2 बाएं जोड़ एक साथ धीमे थे, और प्रत्येक एक स्वतंत्र रूप से तेज था)
  • फिर मैंने धीमी और तेज़ क्वेरी के साथ एक्सप्लेन को निष्पादित किया (बाएं जोड़ों में से एक को जोड़कर)
  • आश्चर्यजनक रूप से, MySQL ने 2 प्रश्नों के बीच पूरी तरह से JOIN ऑर्डर बदल दिए।

इसलिए मैंने एक जोड़ को सीधा होने के लिए मजबूर किया। पिछली जोड़ को पहले पढ़ने के लिए मजबूर किया। इसने MySQL को निष्पादन आदेश को बदलने से रोका और एक आकर्षण की तरह काम किया!


2

मेरे छोटे अनुभव में, एक स्थिति जिसने STRAIGHT_JOINमेरी क्वेरी को 30 सेकंड से 100 मिलीसेकंड तक घटा दिया है, वह यह है कि निष्पादन योजना की पहली तालिका वह तालिका नहीं थी जिसमें स्तंभों द्वारा आदेश दिया गया है

-- table sales (45000000) rows
-- table stores (3) rows
SELECT whatever
FROM 
    sales 
    INNER JOIN stores ON sales.storeId = stores.id
ORDER BY sales.date, sales.id 
LIMIT 50;
-- there is an index on (date, id)

अनुकूलक हिट करने के लिए चुनता है stores पहले यह कारण होगा Using index; Using temporary; Using filesortक्योंकि

यदि ORDER BY या GROUP BY में शामिल पंक्ति में पहली तालिका के अलावा अन्य तालिकाओं के स्तंभ हैं, तो एक अस्थायी तालिका बनाई जाती है।

स्रोत

यहां ऑप्टिमाइज़र को salesपहले इस्तेमाल करने के लिए कहकर थोड़ी मदद की ज़रूरत होती है

sales STRAIGHT_JOIN stores

1
(मैं आपके उत्तर पर अलंकृत हूं।)
रिक जेम्स

2

यदि आपकी क्वेरी समाप्त हो जाती है ORDER BY... LIMIT..., तो यह ऑप्टिमाइज़र को करने से पहले क्वेरी करने के लिए क्वेरी को सुधारने के लिए इष्टतम हो सकता है ।LIMIT JOIN

(यह उत्तर केवल मूल प्रश्न पर ही लागू नहीं होता है STRAIGHT_JOINऔर न ही यह सभी मामलों पर लागू होता है STRAIGHT_JOIN।)

@Accountant م द्वारा उदाहरण के साथ शुरू करते हुए , यह ज्यादातर स्थितियों में तेजी से चलना चाहिए। (और यह संकेत की जरूरत से बचा जाता है।)

SELECT  whatever
    FROM  ( SELECT id FROM sales
                ORDER BY  date, id
                LIMIT  50
          ) AS x
    JOIN  sales   ON sales.id = x.id
    JOIN  stores  ON sales.storeId = stores.id
    ORDER BY  sales.date, sales.id;

टिप्पणियाँ:

  • सबसे पहले, 50 आईडी प्राप्त की जाती हैं। यह विशेष रूप से तेजी के साथ होगा INDEX(date, id)
  • फिर वापस salesआपको केवल 50 "व्हाट्सएप" प्राप्त करने की अनुमति देता है, उन्हें एक टेम्‍प टेबल में इधर उधर किए बिना
  • चूंकि एक उपश्रेणी है, परिभाषा के अनुसार, असंक्रमित, ORDER BYबाहरी क्वेरी में दोहराया जाना चाहिए। (ऑप्टिमाइज़र वास्तव में एक और प्रकार करने से बचने का एक तरीका खोज सकता है।)
  • हां, यह गड़बड़ है। लेकिन यह आमतौर पर तेज होता है।

मैं हिट का उपयोग करने का विरोध कर रहा हूं क्योंकि "भले ही यह आज तेज हो, लेकिन यह कल तेज होने में विफल हो सकता है।"


0

मुझे पता है कि यह थोड़ा पुराना है, लेकिन यहां एक परिदृश्य है, मैं एक निश्चित तालिका को आबाद करने के लिए बैच स्क्रिप्ट कर रहा हूं। कुछ बिंदु पर, क्वेरी बहुत धीमी गति से चली। ऐसा प्रतीत होता है कि ज्वाइनिंग ऑर्डर विशेष रिकॉर्ड पर गलत था:

  • सही क्रम में

यहां छवि विवरण दर्ज करें

  • क्रमांक 1 को बढ़ाकर आईडी को बढ़ाता है। 'अतिरिक्त' फ़ील्ड पर ध्यान दें

यहां छवि विवरण दर्ज करें

  • स्ट्रेट_जॉइन का उपयोग समस्या को ठीक करता है

यहां छवि विवरण दर्ज करें

मिलीसेकंड में सीधे_जॉइन का उपयोग करते हुए लगभग 65 सेकंड के लिए गलत क्रम चलता है


-5
--use 120s, 18 million data
    explain SELECT DISTINCT d.taid
    FROM tvassist_recommend_list_everyday_diverse d, tvassist_taid_all t
    WHERE d.taid = t.taid
      AND t.client_version >= '21004007'
      AND t.utdid IS NOT NULL
      AND d.recommend_day = '20170403'
    LIMIT 0, 10000

--use 3.6s repalce by straight join
 explain SELECT DISTINCT d.taid
    FROM tvassist_recommend_list_everyday_diverse d
    STRAIGHT_JOIN 
      tvassist_taid_all t on d.taid = t.taid 
    WHERE 
     t.client_version >= '21004007'
       AND d.recommend_day = '20170403'

      AND t.utdid IS NOT NULL  
    LIMIT 0, 10000

3
यह आपको लगभग पर्याप्त जानकारी नहीं देता है जब सीधे जोड़ उचित हों।
Hannele
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.