MySQL: आंतरिक प्रश्नों में "ORDER BY" के साथ यूनिअन का अनुकूलन करें


9

मैं बस एक लॉगिंग सिस्टम सेट करता हूं जिसमें एक ही लेआउट के साथ कई टेबल होते हैं।

प्रत्येक डेटा स्रोत के लिए एक तालिका है।

लॉग दर्शक के लिए, मैं चाहता हूं

  • सभी लॉग टेबल को यूनिअन करें ,
  • उन्हें खाते से फ़िल्टर करें ,
  • स्रोत की पहचान के लिए एक छद्म कॉलम जोड़ें ,
  • उन्हें समय के अनुसार क्रमबद्ध करें ,
  • और पेजिंग के लिए उन्हें सीमित करें

सभी तालिकाओं में एक फ़ील्ड होती है, जिसे zeitpunktअनुक्रमित दिनांक / समय स्तंभ कहा जाता है।

मेरा पहला प्रयास था:

(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt AS zeit,
 'hp' AS source FROM is_log AS l WHERE l.account_id = 730)

UNION

(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt,
 'ig' AS source FROM ig_is_log AS l WHERE l.account_id = 730)

ORDER BY zeit DESC LIMIT 10;

आशावादी यहाँ अनुक्रमणिकाओं का उपयोग नहीं कर सकता है क्योंकि दोनों तालिकाओं की सभी पंक्तियाँ उपश्रेणियों द्वारा लौटा दी जाती हैं और बाद में छांटी जाती हैं UNION

मेरा समाधान निम्नलिखित था:

(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt AS zeit,
 'hp' AS source FROM is_log AS l WHERE l.account_id = 730
 ORDER BY l.zeitpunkt DESC LIMIT 10)

UNION

(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt,
 'ig' AS source FROM ig_is_log AS l WHERE l.account_id = 730
 ORDER BY l.zeitpunkt DESC LIMIT 10)

ORDER BY zeit DESC LIMIT 10;

मैं उम्मीद कर रहा था कि क्वेरी इंजन यहाँ अनुक्रमणिका का उपयोग करेगा क्योंकि दोनों उपश्रेणियों को क्रमबद्ध और पहले से ही सीमित किया जाना चाहिए UNION, जो तब विलय और पंक्तियों को क्रमबद्ध करता है।

मैंने वास्तव में सोचा था कि यह होगा, लेकिन EXPLAINक्वेरी पर चलने से मुझे पता चलता है कि उपश्रेणी अभी भी दोनों तालिकाओं को खोजती है।

EXPLAINingउपश्रेणियाँ स्वयं मुझे वांछित अनुकूलन दिखाती हैं, लेकिन UNIONingसाथ में ऐसा नहीं करती हैं।

क्या मैं कुछ भुल गया?

मुझे पता है कि ORDER BYउप- UNIONश्रेणियों के अंदर खंडों को एक के बिना अनदेखा किया जाता है LIMIT, लेकिन एक सीमा है।

संपादित करें:
वास्तव में,account_idस्थिति केबिना भी प्रश्न होंगे।

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

मुझे लॉग रीडर और वास्तविक तालिकाओं के बीच एक तरह की परत रखनी होगी।

संपूर्ण क्वेरी और प्रथम उप-तालिका के साथ-साथ तालिका लेआउट के लिए निष्पादन योजनाएं विस्तार से हैं:

https://gist.github.com/ca8fc1093cd95b1c6fc0


1
इसके लिए सबसे अच्छा सूचकांक यौगिक होगा (account_id, zeitpunkt)। क्या आपके पास ऐसा कोई इंडेक्स है? दूसरा सबसे अच्छा (मुझे लगता है) एकल होगा (zeitpunkt)- लेकिन अगर इसका इस्तेमाल किया जाता है तो दक्षता इस बात पर निर्भर करती है कि पंक्तियां कितनी बार account_id=730दिखाई देती हैं।
ypercube y

2
और क्यों UNION DISTINCT? अतिरिक्त और पहचान कॉलम के कारण, सभी प्रकारों को अलग-अलग करने की आवश्यकता नहीं है, क्योंकि परिणाम सबक्वेरी में अलग-अलग होंगे। का उपयोग करें UNION ALL
ypercube y

1
@ Ypercube के सुझाव के अलावा, मेरा एक प्रश्न है: क्या उन सभी लॉग को एक ही तालिका में रखना बेहतर नहीं होगा, sourceकॉलम के अतिरिक्त के साथ ? इस तरह से आप UNIONअपने सभी डेटा में s और इंडेक्स का उपयोग कर सकते हैं ।
डेज़ो

1
असल में @ypercube, वहाँ शायद भी बिना प्रश्नों हो जाएगा ACCOUNT_ID हालत। DISTINCT झंडा पिछले प्रयासों की एक अवशिष्ट है और क्योंकि परिणाम हमेशा अलग होगा वास्तव में बेकार है और क्योंकि DISTINCT dafualt व्यवहार है। तालिकाओं में पहले से मौजूद हैं और डेटा से भरे हुए हैं। वैसे भी, स्रोत के आधार पर लेआउट में परिवर्तन हो सकते हैं इसलिए मैं उन्हें विभाजित रखना चाहता हूं। इसके अतिरिक्त, लॉगिंग क्लाइंट एक कारण के लिए विभिन्न क्रेडेंशियल्स का उपयोग करते हैं। मुझे लॉग रीडर और वास्तविक तालिकाओं के बीच एक तरह की परत रखनी होगी।
लुकास

ठीक है, लेकिन जाँच करें कि क्या UNION ALLअलग-अलग निष्पादन योजना से पैदावार में बदल रहा है ।
ypercube y

जवाबों:


8

जिज्ञासा से बाहर, आप इस संस्करण की कोशिश कर सकते हैं? यह ऑप्टिमाइज़र को उसी सूचक का उपयोग करने के लिए ट्रिक कर सकता है जो उप-क्षेत्र अलग-अलग उपयोग करेंगे:

SELECT *
FROM
(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt AS zeit,
 'hp' AS source FROM is_log AS l WHERE l.account_id = 730
 ORDER BY l.zeitpunkt DESC LIMIT 10) 
    AS a

UNION ALL

SELECT *
FROM
(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt,
 'ig' AS source FROM ig_is_log AS l WHERE l.account_id = 730
 ORDER BY l.zeitpunkt DESC LIMIT 10)
    AS b

ORDER BY zeit DESC LIMIT 10;

मुझे अब भी लगता है कि आपके पास सबसे अच्छा सूचकांक हो सकता है (account_id, zeitpunkt)। यह 10 पंक्तियों को तेजी से प्राप्त करेगा, और किसी भी चाल की आवश्यकता नहीं होगी।


वांछित परिणाम लाने के लिए आपका संशोधन हुआ। धन्यवाद! बस एक साइड नोट के रूप में: अब तक मुझे यकीन नहीं है कि कौन सा इंडेक्स बेहतर होगा। मैं दोनों का उपयोग भी कर सकता था। मुझे यह देखना होगा कि उपयोगकर्ताओं की संख्या और log entries / userवसीयत कैसे होगी।
लुकास

यदि आपको प्रश्नों के साथ और प्रश्नों की आवश्यकता है account_id=?, तो दोनों को रखें।
ypercube y

@ypercube, +1 यह बहुत चालाक है और मेरी (समान) स्थिति में भी काम करता है! क्या आप बता सकते हैं कि डमी SELECT * FROMट्रिक्स MySQL में यूनियन किए गए प्रश्नों को इंडेक्स के उपयोग में क्यों लपेटते हैं?
dk विटामिन

@ विटामिन: MySQL ऑप्टिमाइज़र बहुत चालाक नहीं है, आमतौर पर जब यहां एक व्युत्पन्न तालिका होती है जैसे (SELECT ...) AS a, यह व्युत्पन्न तालिका को अन्य व्युत्पन्न तालिकाओं और फिर पूरी क्वेरी से अलग से मूल्यांकन और अनुकूलित करने की कोशिश करता है।
ypercube y

@ लुकास, वास्तव में चूंकि आपको यह सुनिश्चित करने की आवश्यकता है कि सूचकांक का उपयोग किया जाता है, उपयोग / जोड़ force indexआपको एक बेहतर समाधान देगा।
पचेरियर 7:15
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.