2010-06-10 12 views
8

Tôi đang cố gắng để tối ưu hóa truy vấn này:Mysql truy vấn chậm: INNER JOIN + ORDER BY nguyên nhân 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; 

Kích thước của bảng là 38k hàng, và 31k và mysql sử dụng "filesort" vì vậy nó được khá chậm. Tôi đã cố gắng sử dụng các chỉ mục khác nhau, không may mắn.

 
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) 

Những loại chỉ số tôi cần phải xác định để tránh mysql sử dụng filesort? Có thể khi trường lệnh không nằm trong mệnh đề where?

update: Profiling kết quả:

 
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:

Bất động truy vấn (một số lĩnh vực boolean hơn, chỉ thêm vô ích)

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;

bộ Rỗng (1,25 giây)

Với ra ORDER BY - 0,01 giây.

 

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

SOLUTION

  1. Query cập nhật để "ORDER BY posts_tags.created_at DESC" (hai thay đổi nhỏ trong mã ứng dụng)
  2. Index thêm: index_posts_tags_on_created_at.

Đó là tất cả!

Trả lời

3

Bạn sẽ cần phải denormalize một chút, và sao chép các lĩnh vực posts.created_at vào bảng post_tags (tôi gọi nó post_created_at, bạn có thể đặt tên cho nó như thế nào bạn muốn):

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; 

và sau đó thêm một chỉ số tới posts_tags trên

(tag_id, post_created_at) 

Điều đó sẽ cho phép truy vấn nhận tất cả bài đăng cho thẻ theo đúng thứ tự mà không có tệp.

+0

Cảm ơn! Tôi đã cập nhật truy vấn để sử dụng posts_tags.created_at để sắp xếp (không cần biết ngày tạo thẻ) và thêm index_posts_tags_on_created_at ... no filesort! :) – Alexander

+0

Có thể thông báo cho người lập kế hoạch truy vấn rằng hai cột trong các bảng khác nhau là giống nhau, vì vậy bạn sẽ không phải chỉ định rõ ràng rằng nó nên sử dụng posts_tags.created_at thay vì posts.created_at? – sorenbs

0

chìa khóa của bạn index_posts_on_created_at được sắp xếp tăng dần nhưng bạn muốn kết quả được sắp xếp giảm dần

+0

Nó sử dụng filesort với cả hai thứ tự sắp xếp ASC và DESC: ( – Alexander

1

Hãy thử thay đổi KEY index_posts_tags_on_post_id_and_tag_id (post_id, tag_id) Key index_posts_tags_tag_id (tag_id) và repost Giải thích.

Phân phối của TagID với Posts_Tags là gì?