2010-06-10 16 views
8

मैं इस क्वेरी अनुकूलन करने के लिए कोशिश कर रहा हूँ:Mysql धीमी क्वेरी: इनर + जुड़ने के द्वारा कारणों filesort

 
SELECT `posts`.* FROM `posts` INNER JOIN `posts_tags` 
    ON `posts`.id = `posts_tags`.post_id 
    WHERE (((`posts_tags`.tag_id = 1))) 
    ORDER BY posts.created_at DESC; 

टेबल के आकार 38k पंक्तियाँ, और 31k है और mysql "filesort" का उपयोग करता है तो यह बहुत हो जाता है धीमी गति से। मैंने अलग-अलग इंडेक्स का उपयोग करने की कोशिश की, कोई भाग्य नहीं।

 
CREATE TABLE `posts` (
    `id` int(11) NOT NULL auto_increment, 
    `created_at` datetime default NULL, 
    PRIMARY KEY (`id`), 
    KEY `index_posts_on_created_at` (`created_at`), 
    KEY `for_tags` (`trashed`,`published`,`clan_private`,`created_at`) 
) ENGINE=InnoDB AUTO_INCREMENT=44390 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

CREATE TABLE `posts_tags` (
    `id` int(11) NOT NULL auto_increment, 
    `post_id` int(11) default NULL, 
    `tag_id` int(11) default NULL, 
    `created_at` datetime default NULL, 
    `updated_at` datetime default NULL, 
    PRIMARY KEY (`id`), 
    KEY `index_posts_tags_on_post_id_and_tag_id` (`post_id`,`tag_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=63175 DEFAULT CHARSET=utf8 
 
+----+-------------+------------+--------+--------------------------+--------------------------+---------+---------------------+-------+-----------------------------------------------------------+ 
| id | select_type | table  | type | possible_keys   | key      | key_len | ref     | rows | Extra              | 
+----+-------------+------------+--------+--------------------------+--------------------------+---------+---------------------+-------+-----------------------------------------------------------+ 
| 1 | SIMPLE  | posts_tags | index | index_post_id_and_tag_id | index_post_id_and_tag_id | 10  | NULL    | 24159 | Using where; Using index; Using temporary; Using filesort | 
| 1 | SIMPLE  | posts  | eq_ref | PRIMARY     | PRIMARY     | 4  | .posts_tags.post_id |  1 |               | 
+----+-------------+------------+--------+--------------------------+--------------------------+---------+---------------------+-------+-----------------------------------------------------------+ 
2 rows in set (0.00 sec) 

सूचकांक मैं filesort का उपयोग कर mysql से बचने के लिए परिभाषित करने की जरूरत किस तरह का? क्या यह संभव है जब ऑर्डर फ़ील्ड क्लॉज में न हो?

अद्यतन: रूपरेखा परिणाम:

 
mysql> show profile for query 1; 
+--------------------------------+----------+ 
| Status       | Duration | 
+--------------------------------+----------+ 
| starting      | 0.000027 | 
| checking query cache for query | 0.037953 | 
| Opening tables     | 0.000028 | 
| System lock     | 0.010382 | 
| Table lock      | 0.023894 | 
| init       | 0.000057 | 
| optimizing      | 0.010030 | 
| statistics      | 0.000026 | 
| preparing      | 0.000018 | 
| Creating tmp table    | 0.128619 | 
| executing      | 0.000008 | 
| Copying to tmp table   | 1.819463 | 
| Sorting result     | 0.001092 | 
| Sending data     | 0.004239 | 
| end       | 0.000012 | 
| removing tmp table    | 0.000885 | 
| end       | 0.000006 | 
| end       | 0.000005 | 
| query end      | 0.000006 | 
| storing result in query cache | 0.000005 | 
| freeing items     | 0.000021 | 
| closing tables     | 0.000013 | 
| logging slow query    | 0.000004 | 
| cleaning up     | 0.000006 | 
+--------------------------------+----------+ 

Update2:

रियल क्वेरी (कुछ और बूलियन क्षेत्रों, अधिक बेकार अनुक्रमित)

SELECT `posts`.* FROM `posts` INNER JOIN `posts_tags` 
    ON `posts`.id = `posts_tags`.post_id 
    WHERE ((`posts_tags`.tag_id = 7971)) 
     AND (((posts.trashed = 0) 
     AND (`posts`.`published` = 1 
     AND `posts`.`clan_private` = 0)) 
     AND ((`posts_tags`.tag_id = 7971))) 
    ORDER BY created_at DESC LIMIT 0, 10;

खाली सेट (1.25 सेकंड)

साथ बाहर आदेश - 0.01s।

 

+----+-------------+------------+--------+-----------------------------------------+-----------------------+---------+---------------------+-------+--------------------------+ 
| id | select_type | table  | type | possible_keys       | key     | key_len | ref     | rows | Extra     | 
+----+-------------+------------+--------+-----------------------------------------+-----------------------+---------+---------------------+-------+--------------------------+ 
| 1 | SIMPLE  | posts_tags | index | index_posts_tags_on_post_id_and_tag_id | index_posts_tags_... | 10  | NULL    | 23988 | Using where; Using index | 
| 1 | SIMPLE  | posts  | eq_ref | PRIMARY,index_posts_on_trashed_and_crea | PRIMARY    | 4  | .posts_tags.post_id |  1 | Using where    | 
+----+-------------+------------+--------+-----------------------------------------+-----------------------+---------+---------------------+-------+--------------------------+ 

समाधान

  1. क्वेरी (ऐप्लिकेशन कोड में दो छोटे परिवर्तन) "posts_tags.created_at DESC द्वारा आदेश" के लिए अद्यतन
  2. सूचकांक कहा: index_posts_tags_on_created_at।

यह सब कुछ है!

उत्तर

3

आप थोड़ा denormalize के लिए, और (मैं इसे post_created_at कहा जाता है, आप इसे नाम दे सकते हैं जैसे आप चाहें) post_tags तालिका में posts.created_at क्षेत्र नकल की आवश्यकता होगी:

CREATE TABLE `posts_tags` (
    `id` int(11) NOT NULL auto_increment, 
    `post_id` int(11) default NULL, 
    `tag_id` int(11) default NULL, 
    `post_created_at` datetime default NULL, 
    `created_at` datetime default NULL, 
    `updated_at` datetime default NULL, 
    PRIMARY KEY (`id`), 
    KEY `index_posts_tags_on_post_id_and_tag_id` (`post_id`,`tag_id`) 
) ENGINE=InnoDB; 

करता है फिर अनुक्रमणिका जोड़ने

(tag_id, post_created_at) 

पर posts_tags कि क्वेरी के सभी पोस्ट एक टैग के लिए, सही क्रम में, filesort बिना प्राप्त करने की अनुमति देगा करने के लिए।

+0

धन्यवाद के साथ filesort का उपयोग करता है! मैं छँटाई (पता करने के लिए टैग निर्माण तिथि की कोई जरूरत नहीं) के लिए posts_tags.created_at उपयोग करने के लिए क्वेरी अद्यतन और index_posts_tags_on_created_at ... कोई और अधिक filesort जोड़ा गया! :) – Alexander

+0

क्या क्वेरी प्लानर को सूचित करना संभव है कि अलग-अलग तालिकाओं में दो कॉलम समान हैं, इसलिए आपको स्पष्ट रूप से निर्दिष्ट नहीं करना होगा कि इसे post.created_at के बजाय post_tags.created_at का उपयोग करना चाहिए? – sorenbs

0

अपने प्रमुख index_posts_on_created_at आरोही क्रमबद्ध किया जाता है, लेकिन आप index_posts_tags_on_post_id_and_tag_id (post_id, tag_id) कुंजी index_posts_tags_tag_id (tag_id) और के बारे में बताएं repost करने के लिए परिणाम उतरते

+0

यह दोनों एएससी और DESC तरह आदेश :( – Alexander

1

कुंजी बदलने का प्रयास करें अनुसार क्रमबद्ध चाहते हैं।

पोस्ट_Tags के साथ टैगआईड्स का वितरण क्या है?

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