2010-06-10 34 views
8

Bu sorgu optimize etmek çalışıyorum FileSort TARAFINDAN + SİPARİŞ JOIN:MySQL yavaş sorgu: İÇ nedenleri

 
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; 

tablo boyutu 38k satır ve 31k ve oldukça alır böylece Mysql "filesort" kullanır yavaş. Farklı indeksler kullanmaya çalıştım, şans yok.

 
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) 

Ben filesort kullanarak mysql önlemek için tanımlamanız gerekir indeksi ne tür? Sipariş alanı fıkralarda olmadığı zaman mümkün mü?

güncelleme: profil oluşturma sonuçları:

 
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:

Gerçek sorgu (biraz daha boolean alanlar, daha yararsız indeksleri)

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;

Boş küme (1.25 sn)

SİPARİŞ BY - 0,01. (App kodunda iki küçük değişiklikler) "posts_tags.created_at DESC ORDER BY" güncellendi

 

+----+-------------+------------+--------+-----------------------------------------+-----------------------+---------+---------------------+-------+--------------------------+ 
| 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    | 
+----+-------------+------------+--------+-----------------------------------------+-----------------------+---------+---------------------+-------+--------------------------+ 

ÇÖZÜM

  1. Sorgu
  2. Endeksi ekledi: index_posts_tags_on_created_at.

Hepsi bu kadar!

cevap

3

Sanki biraz denormalize ve (İstediğin nasıl sayabilirim, o post_created_at denir) post_tags tabloya posts.created_at adresini kopyala gerekir: bir dizin eklemek sonra

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; 

ve sorgu filesort olmadan, doğru sırayla, bir etiket için bütün mesajları edinmesini sağlayacak

(tag_id, post_created_at) 

üzerine posts_tags için.

+0

teşekkür ile filesort kullanır! :) – Alexander

+0

Sorgu planlayıcısına farklı tablolardaki iki sütunun aynı olduğunu bildirmek mümkün mü, bu yüzden posts.created_at yerine posts_tags.created_at kullanması gerektiğini açıkça belirtmeniz gerekmeyecek mi? – sorenbs

0

senin anahtar index_posts_on_created_at artan sıralanır ancak index_posts_tags_on_post_id_and_tag_id (post_id, tag_id) KEY index_posts_tags_tag_id (tag_id) ve açıklar, postalanacak sonuçları

+0

Ben (etiket oluşturma tarihini bilmek gerek yoktur) sıralamak için posts_tags.created_at kullanmak sorgu güncellenerek index_posts_tags_on_created_at ... artık filesort eklendi! Hem ASC ve DESC sıralama düzenleri :( – Alexander

1

KEY değiştirmeyi deneyin azalan sıralanmış istiyorum.

TagID'lerin Posts_Tags ile dağılımı nedir?