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
- Query cập nhật để "ORDER BY posts_tags.created_at DESC" (hai thay đổi nhỏ trong mã ứng dụng)
- Index thêm: index_posts_tags_on_created_at.
Đó là tất cả!
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
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