2013-08-25 4 views
5

मेरे पास start_date और end_date के साथ DATE प्रकार के साथ फ़ील्ड के साथ लगभग 100 मिलियन रिकॉर्ड के साथ एक बड़ी तालिका है। मुझे 2013-08-20 और 2013-08-30 के बीच कुछ दिनांक सीमा के साथ ओवरलैप की संख्या की जांच करने की आवश्यकता है, इसलिए मैं इसका उपयोग करता हूं।दिनांक के आधार पर mysql प्रदर्शन

SELECT COUNT(*) FROM myTable WHERE end_date >= '2013-08-20' 
AND start_date <= '2013-08-30' 

दिनांक कॉलम अनुक्रमित हैं। महत्वपूर्ण बात यह है कि जिस तारीख को मैं ओवरलैप के लिए खोज रहा हूं वह हमेशा भविष्य में है, जबकि तालिका में रिकॉर्ड का मुख्य भाग अतीत में है (97-99 मिलियन के बारे में कहें)। तो, यह प्रश्न अगर मैं एक स्तंभ is_future - TINYINT जोड़ने के लिए, तेजी से हो जाएगा, इसलिए, केवल इस

SELECT COUNT(*) FROM myTable WHERE is_future = 1 
AND end_date >= '2013-08-20' AND start_date <= '2013-08-30' 

की तरह है कि हालत की जाँच करके यह बाकी 97 मिलियन या तो रिकॉर्ड को बाहर निकाल देगा और केवल के लिए तारीख हालत की जाँच करेगा शेष 1-3 मिलियन रिकॉर्ड?

मैं उपयोग MySQL

धन्यवाद

संपादित

mysql इंजन InnoDB, MyISAM

यहाँ है, लेकिन काफी फर्क करेगा कि क्या यह कहना है तालिका बनाने

CREATE TABLE `orders` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `title` 
    `start_date` date DEFAULT NULL, 
    `end_date` date DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 

संपादित 2 @Robert सह के बाद जवाब देने के

विभाजन इस मामले के लिए एक अच्छा विचार की तरह लग रहा है, लेकिन यह मुझे is_future क्षेत्र जब तक कि मैं प्राथमिक कुंजी के रूप में यह परिभाषित के आधार पर विभाजन बनाने के लिए अनुमति नहीं है, अन्यथा मैं निकाल देना चाहिए मेरी मुख्य प्राथमिक कुंजी - आईडी, जो मैं नहीं कर सकता। इसलिए, यदि मैं उस क्षेत्र को प्राथमिक कुंजी के रूप में परिभाषित करता हूं, तो विभाजन का अर्थ है, अगर मैं is_future फ़ील्ड द्वारा प्राथमिक कुंजी की खोज करता हूं तो यह पहले से तेज़ नहीं होगा।

संपादित 3 वास्तविक क्वेरी जहां मैं इस उस समय अवधि की कुछ मुक्त टेबल

SELECT r.id, r.name, r.table_count 
FROM restaurants r 
LEFT JOIN orders o 
ON r.id = o.restaurant_id 
WHERE o.id IS NULL 
OR (r.table_count > (SELECT COUNT(*) 
       FROM orders o2 
       WHERE o2.restaurant_id = r.id AND 
       end_date >= '2013-08-20' AND start_date <= '2013-08-30' 
       AND o2.status = 1 
      ) 
) 

समाधान है कि रेस्तरां का चयन करने के लिए है उपयोग करने की आवश्यकता एक बहुत अधिक अनुसंधान और परीक्षण के बाद मेरे मामले में पंक्तियों की संख्या गिनने का सबसे तेज़ तरीका सिर्फ एक और शर्त जोड़ना था, कि start_date वर्तमान दिनांक से अधिक है (क्योंकि खोज के लिए तिथि सीमा हमेशा भविष्य में होती है)

SELECT COUNT(*) FROM myTable WHERE end_date >= '2013-09-01' 
     AND start_date >= '2013-08-20' AND start_date <= '2013-09-30' 

भी एक इंडेक्स होना आवश्यक है - start_date और end_date फ़ील्ड्स के साथ (धन्यवाद @ सिमकबीन)। परिणामस्वरूप 7 सेकंड से 10 मीटर पंक्तियों के साथ तालिका पर निष्पादन समय - 0.050 सेकंड बन गया।

समाधान 2 (@Robert Co) इस मामले में विभाजन भी काम करता है !! - शायद यह अनुक्रमण से बेहतर समाधान है। या वे दोनों एक साथ लागू किया जा सकता है।

धन्यवाद

+0

महान प्रश्न ... इसे आज़माएं और हमें बताएं। ;) आप 'BETWEEN' का उपयोग क्यों नहीं कर रहे हैं? – DevlshOne

+1

@DevlshOne,: डी, ​​इस मामले में कैसे उपयोग करें? मैं 2 कॉलम की तुलना करता हूं, क्या मैं कर सकता हूं? – dav

+0

क्या आप बिल्ड टेबल स्टेटमेंट और स्टोरेज इंजन के बारे में जानकारी पोस्ट कर सकते हैं, यह मायने रखता है .. –

उत्तर

4

यह table partitioning के लिए एक आदर्श उपयोग केस है। यदि ओरेकल इंटरवल सुविधा इसे MySQL पर बनाता है, तो यह केवल उत्कृष्टता में जोड़ देगा।

+0

वास्तव में यह सुनिश्चित नहीं है कि आपको लगता है कि 'ऑर्डर' तालिका विभाजन से इसे अयोग्य घोषित करती है। यदि आप डेटा को MAXVALUE में नहीं बदलना चाहते हैं, तो आप समय से पहले विभाजन बना सकते हैं। –

+0

मैंने सवाल अपडेट किया। धन्यवाद – dav

+1

विभाजन कुंजी प्राथमिक कुंजी के समान नहीं है। यदि आप विभाजन चुनते हैं, तो अब आपको is_future ध्वज की आवश्यकता नहीं है। मैं अंत तारीख से विभाजन करेंगे। विभाजन को अधिक मत करो। मासिक पर्याप्त होना चाहिए। –

0

मैं एक साधारण परीक्षण किया है, बस tinyint स्तंभ पर एक सूचकांक बनाया। संरचनाएं समान नहीं हो सकती हैं, लेकिन एक सूचकांक के साथ यह काम करता प्रतीत होता है।

http://www.sqlfiddle.com/#!2/514ab/1/0 और देखने के लिए कि चयन गिनती http://www.sqlfiddle.com/#!2/514ab/2/0

देखें निष्पादन वहाँ योजना के लिए सिर्फ एक पंक्ति यह आपके मामले में केवल रिकॉर्ड की कम संख्या पर कार्रवाई होगी जिसका मतलब है कि स्कैन करता है।

तो सरल उत्तर हाँ है, एक सूचकांक के साथ यह काम करेगा।

+1

नहीं, आप कम चयनशीलता वाले कॉलम को इंडेक्स नहीं करते हैं, केवल दो मान 0 - 1 को अनुक्रमित नहीं किया जाना चाहिए .. –

+0

ठीक है मैंने कुछ सीखा, लेकिन फिर जवाब नहीं है, क्योंकि इंडेक्स के बिना यह सभी तीन पंक्तियों का चयन करता है, मैं अनुमान है कि उत्तर तब स्पष्ट है – skv

+1

@RaymondNijland, जब तक आप कॉलम को कवर इंडेक्स में नहीं चाहते हैं, अन्यथा इसे प्रत्येक पंक्ति के लिए डिस्क (ज्यादातर यादृच्छिक) डिस्क io की आवश्यकता होगी। नेवर से नेवर। – newtover

2

तारीख स्तंभ

सूचकांक किस प्रकार अनुक्रमित रहे हैं? एक हैश आधारित इंडेक्स रेंज पूछताछ के लिए कोई उपयोग नहीं है। यदि यह बीटीईई इंडेक्स नहीं है तो इसे अभी बदलें। और आपने हमें * नहीं दिखाया है कि वे अनुक्रमित हैं। क्या एक ही इंडेक्स में दोनों कॉलम हैं? क्या वहां भी अन्य सामान है? क्या ऑर्डर (end_date पहले कॉलम के रूप में दिखाना चाहिए)?

लिपि में निहित प्रकार रूपांतरण कर रहे हैं - इस अनुकूलक द्वारा स्वचालित रूप से नियंत्रित किया जाना चाहिए, लेकिन यह जाँच के लायक है ....

SELECT COUNT(*) FROM myTable WHERE end_date >= 20130820000000 
AND start_date <= 20130830235959 

अगर मैं एक स्तंभ is_future जोड़ने - TINYINT

सबसे पहले, किसी भी उपयोग के लिए, यह आवश्यक होगा कि भविष्य की तारीख तालिका में संग्रहीत कुल डेटा (10% से कम) का एक छोटा सा हिस्सा हो। और यह सिर्फ एक पूर्ण टेबल स्कैन से अधिक कुशल बनाने के लिए है।

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

तीसरा, अगर यह अभी भी डेटा की 3 मिलियन पंक्तियों (और विशेष रूप से, इंडेक्स लुकअप के माध्यम से) को संसाधित करना है तो यह स्मृति में चिपकने वाले डेटा के साथ भी धीमा होने वाला है।

आगे, अनुकूलक को इस सूचकांक का उपयोग करने की संभावना नहीं है (बिना कार्डिनालिटी के कारण)।

+0

मैंने प्रश्न अपडेट किया। इंडेक्स के बारे में - यह एक सामान्य इंडेक्स है जिसे 'वैकल्पिक तालिका ऑर्डर' द्वारा बनाया जा रहा है INDEX एंडडेट (end_date); ',' start_date' के लिए, क्या यह सही नहीं है? – dav

+0

यह इस बात का उत्तर नहीं देता कि यह किस प्रकार की अनुक्रमणिका है - लेकिन आप पाएंगे कि इन्हें छोड़कर और एक ही इंडेक्स (end_date, start_date, ...) पर प्रतिस्थापित करने से बहुत बेहतर काम होगा। और आपके द्वारा प्रदान की गई सबसे पुरानी जानकारी दी गई है, यह शायद (end_date, start_date, restaurant_id) होना चाहिए। टेबल खोजने के लिए आप जिस क्वेरी का उपयोग कर रहे हैं वह इष्टतम – symcbean

+0

से बहुत दूर है, लेकिन यह जानने का तरीका क्या है कि यह किस प्रकार की अनुक्रमणिका है? एक इंडेक्स के साथ इंडेक्स को प्रतिस्थापित किए बिना मैं इस क्वेरी को अनुकूलित करने के लिए और क्या कर सकता हूं? या मैं अन्य क्वेरी के साथ मुफ्त टेबल के साथ रेस्तरां पा सकते हैं? धन्यवाद – dav

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