2009-07-22 17 views
6

मेरे पास एक ब्राउज़ श्रेणी क्वेरी है जो मैं अनुकूलित करने की कोशिश कर रहा हूं। मैं अस्थायी उपयोग के साथ समाप्त हो रहा हूँ; व्याख्या में फाइलॉर्ट का उपयोग करना और क्वेरी 60,000 पंक्तियों के साथ एक श्रेणी पर धीमी है। अगर मैं ऑर्डर को ऑर्डर हटा देता हूं तो क्वेरी बहुत तेजी से चलती है .05 सेकेंड 60,000 पंक्तियां करने के लिए। आदेश के साथ 5 सेकंड के आसपास इसकी धीमी गति से। पार्ट्स में कुछ 500,000 पंक्तियां हैं जैसे Parts_Category।बड़ी तालिका पर क्वेरी द्वारा ऑर्डर अनुकूलित करना MySQL

मैं पार्ट्स (स्थिति, स्तर, गोदाम, अद्यतन) sort_index

कहा जाता है पर एक समूह सूचकांक में सबसे ऊपर है समझाने मेरे पास है | सभी | अस्थायी का उपयोग करना; फाइलों का उपयोग

अन्य सभी अनुक्रमणिका ठीक दिख रहे हैं। क्या कोई मुझे बता सकता है कि समस्या क्या हो सकती है? मैं विचारों से बाहर हूँ। शायद मुझे इस क्वेरी को पुनर्व्यवस्थित करना चाहिए ताकि मैं शायद बेहतर प्रदर्शन कर सकूं?

क्वेरी।

SELECT Parts.*, Image.type, Image.width, Image.height, 
(SELECT name FROM Location_State WHERE id = Parts.state_id) AS state, 
(SELECT name FROM Location_Region WHERE id = Parts.region_id) AS region, 
(SELECT start_date FROM Promotion WHERE id = Parts.promotion_id) AS promotion_start_date, 
(SELECT end_date FROM Promotion WHERE id = Parts.promotion_id) AS promotion_end_date 
FROM (SELECT parts_id FROM Parts_Category WHERE Parts_Category.category_id = '40' 
UNION SELECT parts_id FROM Parts_Category WHERE Parts_Category.main_category_id = '40') cid 
LEFT JOIN Image ON Parts.image_id = Image.id 
JOIN Parts ON Parts.id = cid.parts_id AND Parts.status = 'A' 
ORDER BY Parts.level DESC, Parts.warehouse DESC, Parts.updated DESC LIMIT 0, 15 
 
Table structure for table Parts 

Field Type Null Default 
id int(11) No auto_increment 
image_id int(11) Yes 0 
gallery_id int(11) Yes 0 
image_count int(3) Yes 0 
promotion_id int(11) Yes 0 
country_id int(11) Yes NULL 
state_id int(11) Yes NULL 
region_id int(11) Yes NULL 
city_id int(11) Yes NULL 
area_id int(11) Yes NULL 
updated datetime Yes 0000-00-00 00:00:00 
entered datetime Yes 0000-00-00 00:00:00 
renewal_date date Yes 0000-00-00 
discount_id varchar(10) Yes NULL 
title   varchar(100) Yes 
search_title varchar(255) Yes 
warehouse varchar(50) Yes 
url varchar(255) Yes 
display_url varchar(255) Yes 
friendly_url varchar(100) Yes NULL 
description varchar(255) Yes 
keywords varchar(1000) Yes NULL 
attachment_file varchar(255) Yes 
attachment_caption varchar(255) Yes 
status char(1) Yes 
level tinyint(3) Yes 0 
worldwide tinyint(1) Yes 0 
random_number int(11) Yes NULL 
reminder tinyint(4) Yes NULL 
category_search varchar(1000) Yes 
video_snippet varchar(1000) Yes 
importID int(11) Yes 0 

Indexes 

PRIMARY    518623  id 
random_number INDEX 32201 random_number 
country_id INDEX 1  country_id 
state_id INDEX 8  state_id 
region_id INDEX 5  region_id 
renewal_date INDEX 1  renewal_date 
worldwide INDEX 1  worldwide 
friendly_url INDEX 518623  friendly_url 
promotion_id INDEX 1  promotion_id 
city_id   INDEX 1 city_id 
area_id  INDEX 1  area_id 
zip_code INDEX 2790  zip_code 
importID INDEX 518623  importID 
image_id INDEX 10   image_id 

-------------- 
index_browse_category INDEX 52 
level 
status 
warehouse 
updated 
----------------- 
keywords FULLTEXT 1 
description 
keywords 
category_search 


Parts_Category 

id    int(11)   No auto_increment  
parts_id  int(11)    No 0  
category_id   int(11)    No 0  
main_category_id int(10)    No 0 

Index 

PRIMARY   PRIMARY 519330   id 
category_id   INDEX 519330   category_id 
parts_id 
main_category_id  INDEX 519330    main_category_id 
parts_id 





+0

जॉन, मैंने नीचे एक प्रारंभिक उत्तर दिया है। यद्यपि अपनी क्वेरी को पूरी तरह से अनुकूलित करने के लिए, कृपया मेरे उत्तर में अनुरोध किए गए आइटम प्रदान करें। – hobodave

+0

मैनुअल को मत भूलना! MySQL का एक विशिष्ट पृष्ठ ऑप्टिमाइज़िंग द्वारा ORDER से निपटने वाला है: http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html – zombat

+0

@ जॉन: अपनी समग्र अनुक्रमणिका जांचें। इसे इस क्रम में '(स्थिति, स्तर, गोदाम, अद्यतन)' पर बनाया जाना चाहिए (यह महत्वपूर्ण है)। ऐसा लगता है कि अब यह गलत तरीके से बनाया गया है (पहला 'स्तर', फिर 'स्थिति'), और ऐसा लगता है कि मेरी क्वेरी धीमी क्यों है। अपनी क्वेरी संरचना पोस्ट करते समय, कृपया 'टेबल पार्ट्स बनाएं दिखाएं' चलाएं और उसका आउटपुट पोस्ट करें: यह 'तालिका बनाएं' कथन आउटपुट करेगा जो कॉपी और पेस्ट करना आसान है। – Quassnoi

उत्तर

38

इस रूप में आपकी क्वेरी को फिर से लिखने का प्रयास करें:

SELECT p.*, i.type, i.width, i.height, 
     (SELECT name FROM Location_State WHERE id = p.state_id) AS state, 
     (SELECT name FROM Location_Region WHERE id = p.region_id) AS region, 
     (SELECT start_date FROM Promotion WHERE id = p.promotion_id) AS promotion_start_date, 
     (SELECT end_date FROM Promotion WHERE id = p.promotion_id) AS promotion_end_date 
FROM parts p 
LEFT JOIN 
     image i 
ON  i.id = p.image_id 
WHERE EXISTS (
     SELECT NULL 
     FROM Parts_Category pc 
     WHERE pc.category_id = '40' 
       AND pc.parts_id = p.id 
     UNION ALL 
     SELECT NULL 
     FROM Parts_Category pc 
     WHERE pc.main_category_id = '40' 
       AND pc.parts_id = p.id 
     ) 
     AND p.status = 'A' 
ORDER BY 
     p.status DESC, p.level DESC, p.warehouse DESC, p.updated DESC 
LIMIT 15 

आप कुशलता से काम करने के लिए इस के लिए निम्नलिखित अनुक्रमित की जरूरत है:

parts (status, level, warehouse, updated) -- this one you have 
parts_category (category_id, parts_id) 
parts_category (main_category_id, parts_id) 

अद्यतन:

मैं सिर्फ इस रूप में टेबल बनाया:

DROP TABLE IF EXISTS `test`.`image`; 
CREATE TABLE `test`.`image` (
    `id` int(11) NOT NULL, 
    `type` int(11) NOT NULL, 
    `width` int(11) NOT NULL, 
    `height` int(11) NOT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

DROP TABLE IF EXISTS `test`.`location_region`; 
CREATE TABLE `test`.`location_region` (
    `id` int(11) NOT NULL, 
    `name` varchar(20) NOT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

DROP TABLE IF EXISTS `test`.`location_state`; 
CREATE TABLE `test`.`location_state` (
    `id` int(11) NOT NULL, 
    `name` varchar(20) NOT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

DROP TABLE IF EXISTS `test`.`parts`; 
CREATE TABLE `test`.`parts` (
    `id` int(11) NOT NULL, 
    `status` char(1) NOT NULL, 
    `level` int(11) NOT NULL, 
    `warehouse` int(11) NOT NULL, 
    `updated` int(11) NOT NULL, 
    `state_id` int(11) NOT NULL, 
    `region_id` int(11) NOT NULL, 
    `promotion_id` int(11) NOT NULL, 
    `image_id` int(11) NOT NULL DEFAULT '1', 
    PRIMARY KEY (`id`), 
    KEY `status` (`status`,`level`,`warehouse`,`updated`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

DROP TABLE IF EXISTS `test`.`parts_category`; 
CREATE TABLE `test`.`parts_category` (
    `id` int(11) NOT NULL, 
    `parts_id` int(11) NOT NULL, 
    `category_id` int(11) NOT NULL, 
    `main_category_id` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `ix_pc_cat_parts` (`category_id`,`parts_id`), 
    KEY `ix_pc_main_parts` (`main_category_id`,`parts_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

DROP TABLE IF EXISTS `test`.`promotion`; 
CREATE TABLE `test`.`promotion` (
    `id` int(11) NOT NULL, 
    `start_date` datetime NOT NULL, 
    `end_date` datetime NOT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

और उन्हें नमूना डेटा से भरा:

INSERT 
INTO parts 
SELECT id, 
     CASE WHEN RAND() < 0.1 THEN 'A' ELSE 'B' END, 
     RAND() * 100, 
     RAND() * 100, 
     RAND() * 100, 
     RAND() * 50, 
     RAND() * 50, 
     RAND() * 50, 
     RAND() * 50 
FROM t_source 
LIMIT 500000; 
INSERT 
INTO parts_category 
SELECT id, 
     id, 
     RAND() * 100, 
     RAND() * 100 
FROM t_source 
LIMIT 500000; 
INSERT 
INTO location_state 
SELECT id, CONCAT('State ', id) 
FROM t_source 
LIMIT 1000; 
INSERT 
INTO location_region 
SELECT id, CONCAT('Region ', id) 
FROM t_source 
LIMIT 1000; 
INSERT 
INTO promotion 
SELECT id, 
     '2009-07-22' - INTERVAL RAND() * 5 - 20 DAY, 
     '2009-07-22' - INTERVAL RAND() * 5 DAY 
FROM t_source 
LIMIT 1000; 

क्वेरी ऊपर 30 milliseconds के लिए चलाता है और निम्नलिखित योजना पैदावार:

1, 'PRIMARY', 'p', 'ref', 'status', 'status', '3', 'const', 107408, 'Using where' 
1, 'PRIMARY', 'i', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'test.p.image_id', 1, '' 
6, 'DEPENDENT SUBQUERY', 'pc', 'ref', 'ix_pc_cat_parts', 'ix_pc_cat_parts', '8', 'const,test.p.id', 1, 'Using index' 
7, 'DEPENDENT UNION', 'pc', 'ref', 'ix_pc_main_parts', 'ix_pc_main_parts', '8', 'const,test.p.id', 1, 'Using index' 
, 'UNION RESULT', '<union6,7>', 'ALL', '', '', '', '', , '' 
5, 'DEPENDENT SUBQUERY', 'Promotion', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'test.p.promotion_id', 1, '' 
4, 'DEPENDENT SUBQUERY', 'Promotion', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'test.p.promotion_id', 1, '' 
3, 'DEPENDENT SUBQUERY', 'Location_Region', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'test.p.region_id', 1, '' 
2, 'DEPENDENT SUBQUERY', 'Location_State', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'test.p.state_id', 1, '' 

जैसा कि आप देख सकते हैं, temporary, filesort नहीं, सब कुछ बहुत तेज़ है।

अब आपकी सहायता करने के लिए, मुझे बस यह देखने की ज़रूरत है कि आपकी तालिकाओं को कैसे परिभाषित किया गया है।

+0

धन्यवाद फिर से Quassnoi। बाएं जॉइन छवि पर बाएं जुड़ें के पास वाक्यविन्यास त्रुटि प्राप्त करने के लिए लगता है? – gus

+0

क्या आप अपनी सटीक तालिका परिभाषाएं प्रदान कर सकते हैं, ताकि मैं वाक्यविन्यास जांच सकूं? – Quassnoi

+0

@ जॉन: इस बीच, अभी आज़माएं, मैंने वास्तव में क्लॉज ऑर्डर को गड़बड़ कर दिया है :) – Quassnoi

1

जॉन, समस्या यह है कि आपकी क्वेरी बनाई गई है कि यह व्युत्पन्न तालिका से चयन कर रहा है। व्युत्पन्न तालिका आपके सूचकांक से लाभ नहीं उठा सकती है। यदि आप, बायाँ अपने Location_State, Location_Region, संवर्धन तालिकाओं के लिए शामिल हों के की जरूरत नहीं है तो एक अंदरूनी बजाय शामिल हों का उपयोग करें,

SELECT 
    Parts.*, 
    Image.type, Image.width, Image.height, 
    Location_State.name AS state, 
    Location_Region.name AS region, 
    Promotion.start_date AS promotion_start_date, 
    Promotion.end_date AS promotion_end_date 
FROM Parts 
LEFT JOIN Image ON Parts.image_id = Image.id 
LEFT JOIN Location_State ON Parts.state_id = Location_State.id 
LEFT JOIN Location_Region ON Parts.state_id = Location_Region.id 
LEFT JOIN Promotion ON Parts.promotion_id = Promotion.id 
INNER JOIN Parts_Category ON (Parts_Category.category_id = 40 OR Parts_Category.main_category_id = 40) 
WHERE Parts.status = 'A' 
GROUP BY Parts.id 
ORDER BY Parts.level DESC, Parts.warehouse DESC, Parts.updated DESC LIMIT 0, 15 

नोट: इस प्रकार आपकी क्वेरी को अद्यतन करने का प्रयास करें। यह संभवतः बेहतर प्रदर्शन करेगा।

आगे इस क्वेरी अनुकूल बनाने में सहायता करने के लिए निम्न प्रदान करें: फिर से लिखा क्वेरी मैं प्रदान की (यह होना चाहिए) अपने उदाहरण के रूप में ही काम करता है

SHOW CREATE TABLE Parts; 

, तो भी प्रदान करते हैं:

EXPLAIN <my query here>\G 
+2

'डीईएससी 'खंड को' MySQL' द्वारा अनदेखा किया जाता है। सभी अनुक्रमित मान आरोही क्रम में संग्रहीत हैं। – Quassnoi

+0

लगता है कि आप सही हैं। मैंने कभी MySQL दस्तावेज के उस हिस्से को नहीं देखा। धन्यवाद Quassnoi। – hobodave

+0

धन्यवाद hobodave, अगर मैं श्रेणी के लिए या श्रेणी के लिए उपयोग करता हूं तो मुझे भागों आईडी पर समूह द्वारा समूह जोड़ना होगा क्योंकि भाग कई श्रेणियों में सूचीबद्ध किया जा सकता है, इसलिए हम उन्हें एक ही परिणाम में कई बार नहीं दिखाना चाहते हैं। समूह द्वारा बुराई whne आदेश के साथ मिश्रित है कारण हम यूनियन का उपयोग किया। संघ नहीं सभी – gus

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