2016-03-02 7 views
5

मेरे पास 5 मिलियन से अधिक पंक्तियों की एक तालिका है। जब मैं एक चुनिंदा क्वेरी करता हूं तो इसमें लगभग 20 सेकंड लगते हैं।MYSQL - इंडेक्सिंग और ऑप्टिमाइज़ क्वेरी का चयन करें

CREATE TABLE `CompanyMaster` (
    `CompUID` int(11) NOT NULL AUTO_INCREMENT, 
    `Weburl` varchar(150) DEFAULT NULL, 
    `CompanyName` varchar(200) DEFAULT NULL, 
    `Alias1` varchar(150) DEFAULT NULL, 
    `Alias2` varchar(150) DEFAULT NULL, 
    `Alias3` varchar(150) DEFAULT NULL, 
    `Alias4` varchar(150) DEFAULT NULL, 
    `Created` datetime DEFAULT NULL, 
    `LastModified` datetime DEFAULT NULL, 
    PRIMARY KEY (`CompUID`), 
    KEY `Alias` (`Alias1`,`Alias2`,`Alias3`,`Alias4`) 
) ENGINE=InnoDB AUTO_INCREMENT=5457968 DEFAULT CHARSET=latin1 

यहाँ कि क्वेरी से व्याख्या है:

SELECT CompUID,Weburl FROM `CompanyTable` WHERE (Alias1='match1' AND Alias2='match2')OR Alias3='match3' OR Alias4='match4' 

यहाँ तालिका संरचना है

--------+------------------------------------------------------------------------------------------------------+ 
| id | select_type | table  | type | possible_keys | key | key_len | ref | rows | Extra   | 
+----+-------------+----------+-------+---------------+------+---------+------+---------+----------------------+ 
| 1 | SIMPLE  | CompanyTable | ALL |  Alias  | NULL | NULL  | NULL | 5255929 | Using where | 
+----+-------------+----------+-------+---------------+------+---------+------+---------+----------------------+ 

मैं समग्र सूचकांक Alias इस्तेमाल किया (Alias1, Alias2, Alias3, Alias4) । लेकिन मेरा मानना ​​है कि यह सबसे अच्छा नहीं है। कृपया मुझे इस चयन क्वेरी लुकअप के लिए सही अनुक्रमण का सुझाव दें।

+1

'या Alias3 = 'match3' या Alias4 = 'match4'' क्या पूर्ण तालिका स्कैन मजबूर कर रहा है है पर विचार करें। यह खंड अनिवार्य रूप से अनदेखा है। इस क्वेरी को अनुकूलित करने के लिए, आपको उपनाम 3 और उपनाम 4 पर एक अनुक्रमणिका जोड़नी होगी। – drew010

+0

आप इसे इस तरह के संकेत प्रदान करके अपनी क्वेरी के प्रदर्शन की जांच कर सकते हैं: 'चुनें COMPUID, 'कंपनीटेबल' उपयोग सूचकांक (उपनाम) से Weburl ...'। क्या इससे गति में कोई फर्क पड़ता है? – zedfoxus

+0

निम्नलिखित क्वेरी के शेयर गणना: "'कंपनीटेबल' से गिनती (*) का चयन करें जहां एलियास 1 = 'मैच 1' और एलियास 2 = 'मैच 2';" और "कंपनीटेबल 'से गिनती (*) का चयन करें जहां एलियास 1 =' मैच 3 '" और "कंपनीटेबल' से गिनती चुनें (*) जहां एलियास 1 = 'मैच 4"। –

उत्तर

3

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

OR या उपनाम 3 (या उपनाम 4) खंड इस नियम का उल्लंघन करते हैं क्योंकि यह कहता है "मुझे कोई परवाह नहीं है कि बाएं हिस्सों (उपनाम 1 या उपनाम 2 (या ऊर्फ 3)) क्या हैं, क्योंकि मैं उन पर निर्भर नहीं हूं"।

एक पूर्ण टेबल स्कैन तब यह देखने के लिए आवश्यक है कि उपनाम 3 (या उपनाम 4) मान हैं जो शर्तों को पूरा करते हैं।

संभावित इस हालत में उपयोगी सूचकांक होगा:

  • सूचकांक (alias1, alias2): alias1 और alias2 इस समग्र सूचकांक
  • सूचकांक (alias3)
  • सूचकांक (alias4) को शामिल किया गया

वास्तविक आंकड़े and plan selection और जांच की आवश्यकता है - लेकिन कम से कम अब प्रश्न योजनाकार के पास बुद्धिमान काम करने के लिए कुछ है एच।


कहा कि जा रहा है - और मुझे यकीन है कि क्या एक "उर्फ" की भूमिका है नहीं कर रहा हूँ - फ़ायदेमंद साबित हो सकता तालिका को सामान्य बनाने में। निम्नलिखित अर्थशास्त्र को थोड़ा बदलता है क्योंकि यह "ऊर्फ स्थिति" को छोड़ देता है (जिसे वापस जोड़ा जा सकता है) और अर्थपूर्ण शुद्धता के लिए सत्यापित किया जाना चाहिए।

CREATE TABLE `CompanyMaster` (
    `CompUID` int(11) NOT NULL AUTO_INCREMENT 
,`CompanyName` varchar(200) DEFAULT NULL 
,PRIMARY KEY (`CompUID`) 
) 

-- (This establishes a unique alias-per-company, which may be incorrect.) 
CREATE TABLE `CompaniesAliases` (
    `CompUID` int(11) NOT NULL 
,`Alias` varchar(150) NOT NULL 
    -- Both CompUID and Alias appear in 'first' positions: 
    -- CompUID for Join, Alias for filter 
,PRIMARY KEY (`CompUID`, `Alias`) 
,KEY (`Alias`) 
-- Alternative, which may change plan selection by eliminating options: 
-- ,PRIMARY KEY (`Alias`, `CompUID`) -- and no single KEY/index on Alias or CompUID 
,FOREIGN KEY(CompUID) REFERENCES CompanyMaster(CompUID) 
) 

यह तो लगभग मूल के समान पूछे जा सकता है, अलग किया जा रहा है यह जो "उर्फ" मैचों की परवाह नहीं करता कि जो मूल्य:

-- AND constructed by joins (could also use GROUP BY .. HAVING COUNT) 
SELECT c.CompUID FROM `CompanyTable` c 
JOIN `CompaniesAliases` ac1 
ON ac1.CompUID = c.CompUID AND Alias = 'match1' 
JOIN `CompaniesAliases` ac2 
ON ac2.CompUID = c.CompUID AND Alias = 'match2' 

-- OR constructed by union(s) 
UNION 
SELECT c.CompUID FROM `CompanyTable` c 
JOIN `CompaniesAliases` ac1 
ON ac1.CompUID = c.CompUID AND (Alias = 'match3' OR Alias = 'match4') 

मैं करने के लिए इस तरह के एक प्रश्न उम्मीद करेंगे एसक्यूएल सर्वर में कुशलतापूर्वक कार्यान्वित किया जा सकता है - MySQL के साथ वाईएमएमवी।

0

मैं निम्नलिखित समाधान का सुझाव दूंगा, एक जटिल_alias_field के साथ एक टेबल बनाएं। यह आपके डेटा को थोड़ा बढ़ाता है, और आपका डेटा अब अनावश्यक है, लेकिन मुझे लगता है कि यह एक सरल सीधा समाधान है।

1।टेबल

CREATE TABLE `CompanyMaster` (
`CompUID` int(11) NOT NULL AUTO_INCREMENT, 
    `Weburl` varchar(150) DEFAULT NULL, 
    `CompanyName` varchar(200) DEFAULT NULL, 
    `Alias1` varchar(150) DEFAULT NULL, 
    `Alias2` varchar(150) DEFAULT NULL, 
    `Alias3` varchar(150) DEFAULT NULL, 
    `Alias4` varchar(150) DEFAULT NULL, 
    `Created` datetime DEFAULT NULL, 
    `LastModified` datetime DEFAULT NULL, 
    `ComplexAliasQuery` BOOLEAN DEFAULT FALSE, 
    PRIMARY KEY (`CompUID`), 
    KEY `Alias` (`Alias1`,`Alias2`,`Alias3`,`Alias4`), 
    KEY `AliasQuery` (`ComplexAliasQuery`) 
) ENGINE=InnoDB AUTO_INCREMENT=5457968 DEFAULT CHARSET=latin1; 

2. बनाएं Alias4

अपने नए फील्ड ComplexAliasQuery

UPDATE CompanyMaster set ComplexAliasQuery = TRUE WHERE (Alias1='match1' AND Alias2='match2')OR Alias3='match3' OR Alias4='match4'; 

3. भरें फील्ड्स Alias1, Alias2, Alias3 में से एक को अद्यतन करने के लिए, बस अद्यतन करने के लिए ComplexAliasQuery भी भरें। यदि आप ट्रिगर का उपयोग नहीं कर सकते हैं, तो आप शायद एक ट्रिगर http://dev.mysql.com/doc/refman/5.7/en/trigger-syntax.html या अपने कोड में ऐसा कर सकते हैं, क्योंकि आप क्लस्टर चला रहे हैं।

4. अपने सरल क्वेरी सूचकांक

+----+-------------+---------------+------+---------------+------+---------+------+------+-------------+ 
| id | select_type | table   | type | possible_keys | key | key_len | ref | rows | Extra  | 
+----+-------------+---------------+------+---------------+------+---------+------+------+-------------+ 
| 1 | SIMPLE  | CompanyMaster | ALL | NULL   | NULL | NULL | NULL | 1 | Using where | 
+----+-------------+---------------+------+---------------+------+---------+------+------+-------------+ 

एक और समाधान

मारने के साथ अंत

SELECT CompUID,Weburl FROM `CompanyMaster` WHERE ComplexAliasQuery IS TRUE; 

पर है आप अपनी तालिका में क्षेत्र की तरह न तो कंपनीमास्टर, आप इसे आउटसोर्स कर सकते हैं एक नई तालिका में और इसे इंडेक्सअलीस कॉम्पैनीमास्टर कहा जाता है और फिर बस इस तालिका में शामिल हों।

0

उपरोक्त में से कोई भी नहीं। स्कीमा फिर से डिजाइन करें।

यदि 4 एलियस एक कंपनी के लिए समानार्थक हैं, तो तालिका में उनमें से एक सरणी चलाएं, उन्हें दूसरी तालिका में ले जाएं। (User2864740 वहाँ आधे रास्ते मिल गया है, मैं सभी तरह से जाने के लिए कह रहा हूँ।)

CREATE TABLE `CompanyMaster` (
    `CompUID` int(11) NOT NULL AUTO_INCREMENT, 
    `Weburl` varchar(150) DEFAULT NULL, 
    `CompanyName` varchar(200) DEFAULT NULL, 
    `Created` datetime DEFAULT NULL, 
    `LastModified` datetime DEFAULT NULL, 
    PRIMARY KEY (`CompUID`), 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

CREATE TABLE `CompaniesAliases` (
    `CompUID` int(11) NOT NULL, 
    `Alias` varchar(150) NOT NULL, 
    PRIMARY KEY (Alias) -- Assuming no two companies can have the same Alias 
    KEY (CompUID) 
) ENGINE=InnoDB; 

(आप वास्तव में InnoDB के लिए सभी तालिकाओं में परिवर्तित करना चाहिए।)

अब, आपकी मूल क्वेरी

SELECT CompUID, Weburl 
    FROM `CompanyTable` 
    JOIN CompaniesAliases USING(CompUID) 
    WHERE Alias IN ('match1', 'match2', 'match3', 'match4'); 
हो जाता है

और यह बहुत तेज़ होगा।

आप कंपनी का नाम और उसके उपनाम को दिखाने के लिए की जरूरत है,

SELECT CompanyName, 
     GROUP_CONCAT(Alias) AS 'Also known as' 
    FROM `CompanyTable` 
    JOIN CompaniesAliases USING(CompUID) 
    WHERE ... 
    GROUP BY CompUID; 
संबंधित मुद्दे