2010-12-07 14 views
7

मेरे पास निम्न है जो अपने आप चलाते समय बहुत तेज़ है, लेकिन जब मैं इसे कई entity_id के लिए कर रहा हूं, तो क्वेरी लंबे और लंबे समय तक लगने लगती हैं (लूप एक PHP foreach है) उदाहरण के लिए यह क्वेरी केवल 0.078 लेता है लेकिन लूप के भीतर एक अलग इकाई पर एक ही क्वेरी 2.1 सेकंड तक ले जाती है, प्रश्न लूप में रखे गए अधिक इकाइयों को धीमे और धीमे लगते हैं। ऐसा क्यों है? और मैं क्वेरी को कैसे सुधार/अनुकूलित कर सकता हूं?mysql क्वेरी स्पीड ऑप्टिमाइज़ेशन

foreach($entity_ids as $entity_id) { 
    SELECT COUNT(*) as prev, DATE_FORMAT(`created`, '%Y%m%d') AS date_group 
    FROM articles_entities 
    WHERE entity_id = '$entity_id' 
    AND `created` >= DATE_SUB(CURDATE(), INTERVAL 10 DAY) 
    GROUP BY date_group 

    // store result 
} 

मैं निम्न तालिका संरचना है:

CREATE TABLE `articles_entities` (
    `id` CHAR(36) NOT NULL, 
    `article_id` CHAR(36) NOT NULL, 
    `entity_id` CHAR(36) NOT NULL, 
    `created` DATETIME DEFAULT NULL, 
    `modified` DATETIME DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `article_id` (`article_id`), 
    KEY `entity_id` (`entity_id`), 
    KEY `created` (`created`) 
) ENGINE=MYISAM DEFAULT CHARSET=utf8; 

उत्तर

7

ऐसा लगता है कि आपके पास आईडी की सरणी है, फिर अपनी तालिका से रिकॉर्ड खींचना चाहते हैं (एक तरह से आपके कथन द्वारा नियंत्रित) जहां आईडी फ़ील्ड सरणी मानों में से किसी एक से मेल खाता है।

एकाधिक SQL कथन चलाने के लिए PHP में एक लूप का उपयोग करने के बजाय, सबसे अच्छी बात यह है कि एक मास्टर स्टेटमेंट बनाएं और परिणामों को संभालने के लिए PHP का उपयोग करें। आप एसक्यूएल IN कथन का उपयोग यह पूरा कर सकते हैं:

// where $entity_ids is an array eg 1,2,3,4,5 

    $sql="SELECT entity_id AS 'alt_entity_id', COUNT(entity_id) as prev, DATE_FORMAT(`created`, '%Y%m%d') AS 'date_group' 
    FROM articles_entities 
    WHERE entity_id IN ".implode(",",$entity_ids)." 
    AND `created` >= DATE_SUB(CURDATE(), INTERVAL 10 DAY) 
    GROUP BY date_group, entity_id"; 
    // you may wish to revese the group fields, as you require, you may also wish to change the count field to date_group, depending on what you wish to be counted 

इस मूल प्रश्न एक बार चलाया जाएगा, सब आईडी मूल्यों तुम हो, दोनों का दिनांक और पारित कर दिया आईडी मूल्य के आधार पर वर्गीकृत के लिए। फिर आप लौटाए गए परिणाम से विशिष्ट आईडी के परिणामों को फ़िल्टर करने के लिए PHP का उपयोग कर सकते हैं।

यह किसी क्वेरी के निष्पादन को लूप करके उत्पादित ओवरहेड से कहीं अधिक कुशल है।

entity_id | count(entity_id) | date_group 
----------|------------------|------------ 
    1  |  3   | 2010-04-01 
    1  |  3   | 2010-03-01 
    1  |  3   | 2010-02-01 
    2  |  2   | 2010-01-01 
    2  |  2   | 2010-02-01 
    3  |  1   | 2010-06-01 
    4  |  2   | 2010-06-01 
    4  |  2   | 2010-02-01 
+0

उत्तर से लापता केवल एक चीज का चयन कर रहा था, entity_id AS alt_entity_id के रूप में मैं काम कर सकता था कि प्रत्येक इकाई कौन सा इकाई थी (ध्यान दें कि मैं केवल entity_id का चयन नहीं कर सकता क्योंकि यह गलत परिणाम देता है। (मुझे समूह को स्वैप करना होगा। अगर आप अपना जवाब अपडेट करते हैं तो मैं इसे स्वीकार करूंगा। – Lizard

+0

खुशी है कि यह मदद मिली है, मैंने अपडेट किया है डी :) – SW4

2

मैं नहीं जानता कि जहां आप अपने पाश के लिए इकाई मान हो रही है, लेकिन एक पाश के भीतर इस क्वेरी को निष्पादित हमेशा एक हो जाएगा बड़ा प्रदर्शन ओवरहेड। यदि आप पिछले SQL क्वेरी से entity_ids प्राप्त कर रहे हैं, तो यह आपके SQL को लूप क्वेरी के साथ प्रारंभिक क्वेरी में शामिल होने के लिए पुन: सक्रिय करने के लिए और अधिक समझ सकता है ताकि आप एक ही SQL क्वेरी में आवश्यक सभी डेटा लौट रहे हों।

+0

मैं PHP पाश – Lizard

+0

कहाँ $ entity_ids से आता है जोड़ लिया है:

आपका लौटे resultset कुछ ऐसी दिखाई देगी? –

+0

मैंने पहले उसी तालिका से आलेखों का चयन किया है जो एक विशिष्ट मानदंड (अलग-अलग दिनांक सीमा) से मेल खाते हैं, और इसकी इकाइयों को वापस लौटाते हैं – Lizard

0

शायद आप कितनी संस्थाओं से निपट रहे हैं?

क्या आप आवश्यक प्रविष्टियों को एक अलग तालिका में सम्मिलित कर सकते हैं और एकाधिक प्रश्नों के बजाय, शामिल हो सकते हैं?

0

एक सरणी में सभी आईडी ले लो, यह में शामिल होने के एक स्ट्रिंग के रूप में और प्रयोग "जहाँ में" अनुकूलित रास्ता

$enitityIDS = array(); 
    foreach($entity_ids as $entity_id) { 
     $enitityIDS[]=$entity_id; 
    } 
    $entityIDString = join(",",$enitityIDS); 

तो

SELECT COUNT(*) as prev, DATE_FORMAT(`created`, '%Y%m%d') AS date_group 
    FROM articles_entities 
    WHERE entity_id in (".$entityIDString.") 
    AND `created` >= DATE_SUB(CURDATE(), INTERVAL 10 DAY) 
    GROUP BY date_group, entity_id 

इष्टतम मार्ग

में जानकारी पाने के लिए
+1

में क्वेरी की श्रृंखला निष्पादित करने की आवश्यकता नहीं है, यह न भूलें कि आपको क्वेरी को समूहबद्ध करने की भी आवश्यकता है आईडी फ़ील्ड, अन्यथा आईएन क्लॉज का नतीजा अलग-अलग – SW4

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