2012-07-23 11 views
5

यदि मेरे पास नीचे दिए गए कथन की तरह एक चुनिंदा कथन है, तो इंडेक्स में कौन सा ऑर्डर और कॉलम शामिल किया जाना चाहिए?इंडेक्स कॉलम और ऑर्डर

SELECT MIN(BenchmarkID), 
     MIN(BenchmarkDateTime), 
     Currency1, 
     Currency2, 
     BenchmarkType 
FROM Benchmark 
     INNER JOIN MyCurrencyPairs ON Currency1 = Pair1 
          AND Currency2 = Pair2 
WHERE BenchmarkDateTime > IN_BeginningTime 
GROUP BY Currency1, Currency2, BenchmarkType; 

आइटम गौर करने योग्य

  • बेंचमार्क तालिका पंक्तियों के अरबों होगा
  • MyCurrencyPairs तालिका एक स्थानीय तालिका कम से कम 10 रिकॉर्ड होगा कि है
  • IN_BeginningTime एक इनपुट पैरामीटर है
  • कॉलम मुद्रा 1 और मुद्रा 2 VARCHARs
  • कॉलम बेंचमार्क आईडी और बेंचमार्क टाइप हैं INTs
  • कॉलम BenchmarkDateTime एक datetime (उम्मीद है कि स्पष्ट था)

मैं CURRENCY1, Currency2, BenchmarkType, BenchmarkDateTime, और BenchmarkID साथ एक सूचकांक बना लिया है, लेकिन मैं गति मैं चाहता था नहीं मिल रहा था। क्या मैं एक बेहतर सूचकांक बना सकता हूं?


संपादित करें # 1: किसी ने नीचे दिए गए समझाए गए परिणामों का अनुरोध किया। मुझे पता है अगर कुछ और

enter image description here


# संपादित 2 की जरूरत है चलो: किसी DDL का अनुरोध किया (मैं इस बयान बनाने है संभालने हूँ) दो तालिकाओं के लिए:

(इस बेंचमार्क तालिका डेटाबेस में मौजूद है)

CREATE TABLE `benchmark` (
    `SequenceNumber` INT(11) NOT NULL, 
    `BenchmarkType` TINYINT(3) UNSIGNED NOT NULL, 
    `BenchmarkDateTime` DATETIME NOT NULL, 
    `Identifier` CHAR(6) NOT NULL, 
    `Currency1` CHAR(3) NULL DEFAULT NULL, 
    `Currency2` CHAR(3) NULL DEFAULT NULL, 
    `AvgBMBid` DECIMAL(18,9) NOT NULL, 
    `AvgBMOffer` DECIMAL(18,9) NOT NULL, 
    `AvgBMMid` DECIMAL(18,9) NOT NULL, 
    `MedianBMBid` DECIMAL(18,9) NOT NULL, 
    `MedianBMOffer` DECIMAL(18,9) NOT NULL, 
    `OpenBMBid` DECIMAL(18,9) NOT NULL, 
    `ClosingBMBid` DECIMAL(18,9) NOT NULL, 
    `ClosingBMOffer` DECIMAL(18,9) NOT NULL, 
    `ClosingBMMid` DECIMAL(18,9) NOT NULL, 
    `LowBMBid` DECIMAL(18,9) NOT NULL, 
    `HighBMOffer` DECIMAL(18,9) NOT NULL, 
    `BMRange` DECIMAL(18,9) NOT NULL, 
    `BenchmarkId` INT(11) NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY (`BenchmarkId`), 
    INDEX `NextBenchmarkIndex01` (`Currency1`, `Currency2`, `BenchmarkType`), 
    INDEX `NextBenchmarkIndex02` (`BenchmarkDateTime`, `Currency1`, `Currency2`, `BenchmarkType`, `BenchmarkId`), 
    INDEX `BenchmarkOptimization` (`BenchmarkType`, `BenchmarkDateTime`, `Currency1`, `Currency2`) 
) 

(मैं अपने दिनचर्या में MyCurrencyPairs तालिका बना रहा हूं)

CREATE TEMPORARY TABLE MyCurrencyPairs 
    (
     Pair1 VARCHAR(50), 
     Pair2 VARCHAR(50) 
    ) ENGINE=memory; 
    CREATE INDEX IDX_MyCurrencyPairs ON MyCurrencyPairs (Pair1, Pair2); 
+0

क्या आप एक एक्सप्लान <चयन विवरण यहां चला सकते हैं> और परिणाम पोस्ट कर सकते हैं। – FreudianSlip

+0

व्याख्या के लिए धन्यवाद। मुद्रा 1 और 2 फ़ील्ड, क्या वे एक कारण के लिए वर्चर हैं? यानी पाठ है? यदि हां, तो क्या कोई तरीका है कि आप उन्हें लुकअप में परिवर्तित कर सकते हैं ताकि फील्ड प्रकार को आईएनटी में बदला जा सके? यानी "जीबीपी" => 1, "यूएसडी" => 2 – FreudianSlip

+0

दुख की बात नहीं ... यह एक ऐसी प्रणाली है जो यहां थोड़ी देर रही है और यह एक बड़ा बदलाव होगा। मेरी इच्छा है कि मूल वास्तुकार ने ऐसा किया था ... कोई विचार नहीं कि आप VARCHARs पर सबकुछ मिलान करने का प्रयास क्यों करेंगे ..... – Miles

उत्तर

1

BenchMarkDateTime आपके सूचकांक में पहला स्तंभ होना चाहिए।

नियम यह है कि, यदि आप एक समग्र सूचकांक का केवल एक हिस्सा उपयोग करते हैं, तो उपयोग किया जाने वाला हिस्सा प्रमुख हिस्सा होना चाहिए।

दूसरा, समूह को इंडेक्स से मेल खाना चाहिए।

कुछ प्रदर्शन बेहतर होगा अगर आप अपनी क्वेरी को ">" के बजाय ">" का उपयोग कर सकते हैं जो एक रेंज चेक क्वेरी है।

0

मुख्य समस्या यह है कि MySQL सीधे एकत्रीकरण को संभालने के लिए सूचकांक का उपयोग नहीं कर सकता है। यह MyCurrencyPairs के साथ जुड़ने के कारण है और यह तथ्य है कि आप MIN(BenchmarkId) के लिए पूछ रहे हैं जबकि BenchmarkDateTime पर रेंज की स्थिति भी है। बेहतर निष्पादन योजना प्राप्त करने के लिए इन दोनों को समाप्त करने की आवश्यकता है।

की पहली आवश्यकता अनुक्रमित पर एक नज़र और जिसके परिणामस्वरूप क्वेरी करते हैं:

ALTER TABLE benchmark 
    ADD KEY `IDX1` (
    `Currency1`, 
    `Currency2`, 
    `BenchmarkType`, 
    `BenchmarkDateTime` 
), 
    ADD KEY `IDX2` (
    `Currency1`, 
    `Currency2`, 
    `BenchmarkType`, 
    `BenchmarkId`, 
    `BenchmarkDateTime` 
); 

SELECT 
    (
    SELECT 
     BenchmarkId 
    FROM 
     benchmark FORCE KEY (IDX2) 
    WHERE 
     Currency1 = ob.Currency1 AND 
     Currency2 = ob.Currency2 AND 
     BenchmarkType = ob.BenchmarkType 
     AND BenchmarkDateTime > IN_BeginningTime 
    ORDER BY 
     Currency1, Currency2, BenchmarkType, BenchmarkId 
    LIMIT 1 
) AS BenchmarkId 
    ob.* 
FROM 
    (
    SELECT 
     MIN(BenchmarkDateTime), 
     Currency1, 
     Currency2, 
     BenchmarkType 
    FROM 
     benchmark 
    WHERE 
     BenchmarkDateTime > IN_BeginningTime 
    GROUP BY 
     Currency1, Currency2, BenchmarkType 
) AS ob 
INNER JOIN 
    MyCurrencyPairs ON Currency1 = Pair1 AND Currency2 = Pair2; 

पहला परिवर्तन है कि GROUP BY हिस्सा अपनी ही सबक्वेरी में होता है।इसका मतलब यह है कि यह Currency1, Currency2, BenchmarkType के सभी संयोजन उत्पन्न करता है, यहां तक ​​कि जो MyCurrencyPairs में दिखाई नहीं देते हैं, लेकिन जब तक कि बहुत सारे संयोजन नहीं होते हैं, तथ्य यह है कि MySQL अब ऑपरेशन करने के लिए एक इंडेक्स का उपयोग कर सकता है, इसे तेज़ी से बनाना चाहिए। यह सबक्वायरी अस्थायी तालिका या एक फाइलोर्ट की आवश्यकता के बिना IDX1 का उपयोग करता है।

दूसरा परिवर्तन MIN(BenchmarkId) भाग के अपने स्वयं के उपखंड में अलगाव है। उस सबक्वायरी में सॉर्टिंग को आईडीएक्स 2 का उपयोग करके संभाला जा सकता है, इसलिए यहां कोई सॉर्टिंग की आवश्यकता नहीं है। FORCE KEY (IDX2) संकेत और यहां तक ​​कि "निश्चित-मूल्य" कॉलम Currency1, Currency2 और BenchmarkTypeORDER में दिखाई देते हैं- MySQL अनुकूलक सही चीज़ करने के लिए आवश्यक है। फिर, यह एक व्यापार बंद है। यदि अंतिम परिणाम सेट बड़ा है तो सबक्वायरी नुकसान हो सकती है, लेकिन मुझे लगता है कि कई पंक्तियां नहीं हैं।

कि क्वेरी को समझाते हुए निम्न क्वेरी योजना देता है (अरुचिकर कॉलम पठनीयता के लिए गिरा दिया):

+----+--------------------+-----------------+-------+---------+------+---------------------------------------+ 
| id | select_type  | table   | type | key_len | rows | Extra         | 
+----+--------------------+-----------------+-------+---------+------+---------------------------------------+ 
| 1 | PRIMARY   | <derived3>  | ALL | NULL | 1809 |          | 
| 1 | PRIMARY   | MyCurrencyPairs | ref | 106  | 2 | Using where       | 
| 3 | DERIVED   | benchmark  | range | 17  | 1225 | Using where; Using index for group-by | 
| 2 | DEPENDENT SUBQUERY | benchmark  | ref | 9  | 520 | Using where; Using index    | 
+----+--------------------+-----------------+-------+---------+------+---------------------------------------+ 

हम देखते हैं कि सभी दिलचस्प भागों ठीक से अनुक्रमित के अंतर्गत आते हैं, और हम न तो अस्थायी तालिकाओं और न ही filesorts आवश्यकता होती है।

मेरे परीक्षण डेटा पर समय यह संस्करण दिखाता है कि यह संस्करण लगभग 20 गुना तेज (1.07 बनाम 0.05 एस) है, लेकिन मेरे पास मेरी बेंचमार्क तालिका में केवल 1.2 मिलियन पंक्तियां हैं और डेटा वितरण संभवतः बंद है, इसलिए YMMV।

+0

भले ही यह आपके लिए काम न करे, मैं जानना चाहूंगा कि हम किस समय के बारे में बात कर रहे हैं। मुझे लगता है कि यह 1 सेकंड रेंज में काफी नहीं है, लेकिन क्या हम अभी भी सेकंड्स बोल रहे हैं, या यह मिनट या घंटे भी है? –

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