改进此查询索引的想法

时间:2012-01-26 03:19:55

标签: mysql

我觉得以下查询太慢了:

(1679.1ms)
SELECT  `media_files` . * 
FROM  `media_files` 
INNER JOIN  `playlist_media_files` ON  `media_files`.`id` =  `playlist_media_files`.`media_file_id` 
WHERE  `media_files`.`type` 
IN (
'AudioFile'
)
AND  `playlist_media_files`.`playlist_id` =7
ORDER BY media_files.artist ASC , media_files.release_year ASC , media_files.album ASC , media_files.disc_number ASC , media_files.position ASC 

说明:

+----+-------------+----------------------+--------+---------------------------------------------------------------------------------------+-------------------------------------------+---------+---------------------------------------------------------+------+---------------------------------+
| id | select_type | table                | type   | possible_keys                                                                         | key                                       | key_len | ref                                                     | rows | Extra                           |
+----+-------------+----------------------+--------+---------------------------------------------------------------------------------------+-------------------------------------------+---------+---------------------------------------------------------+------+---------------------------------+
|  1 | SIMPLE      | playlist_media_files | ref    | index_playlist_media_files_on_playlist_id,index_playlist_media_files_on_media_file_id | index_playlist_media_files_on_playlist_id | 4       | const                                                   | 3782 | Using temporary; Using filesort |
|  1 | SIMPLE      | media_files          | eq_ref | PRIMARY,index_media_files_on_type                                                     | PRIMARY                                   | 4       | mydb.playlist_media_files.media_file_id                 |    1 | Using where                     |
+----+-------------+----------------------+--------+---------------------------------------------------------------------------------------+-------------------------------------------+---------+---------------------------------------------------------+------+---------------------------------+

每列都已编入索引。 任何MySQL专家都可以通过查看解释来说明如何改进它?

多个ORDER BY正在扼杀表现。

修改:从评论中删除私人网址

更新:对于延迟的ORDER BY排序,我似乎可以执行类似concat(..fields..) AS sort的操作。

2 个答案:

答案 0 :(得分:1)

对于此查询,您可能会从(playlist_id,media_file_id)表中playlist_media_files上的复合索引中受益,这将使mysql仅使用此索引来知道从{{1}读取哪一行无需从media_files读取实际数据,即可查看满足playlist_media_files条件的每一行media_file_id的值(很多都是这样)。

您应该看到第一行解释输出的其他playlist_id = 7

Mysql仍然需要创建临时表来按如此多的列对其进行排序,但在内存中排序4k行并不是那么昂贵。

所以基本上尝试:

using index

并查看结果。

编辑:我试图在我的测试数据库上模拟相同的问题,创建相同的表并使用php填充随机400k行,尝试获得类似的索引基数。 如果没有复合索引,则同一查询具有以下执行计划:

ALTER TABLE `playlist_media_files` 
  ADD INDEX `playlist_media_composite` ( `playlist_id` , `media_file_id` ) ;

平均结果是:

1   SIMPLE  playlist_media_files    ref     playlist_id,media_file_id   playlist_id     4   const                                       3925    Using temporary; Using filesort
1   SIMPLE  media_files             eq_ref  PRIMARY                     PRIMARY         4   test.playlist_media_files.media_file_id     1       Using where

添加综合索引并执行Showing rows 0 - 29 ( 2,702 total, Query took 0.0359 sec) 解释后显示:

ANALYZE TABLE playlist_media_files

平均结果:

1   SIMPLE  playlist_media_files    ref     playlist_id,media_file_id,playlist_media_composite  playlist_media_composite    4   const                                       3925    Using index; Using temporary; Using filesort
1   SIMPLE  media_files             eq_ref  PRIMARY                                             PRIMARY                     4   test.playlist_media_files.media_file_id     1       Using where

然而,在这两种情况下,排序都是在内存中完成的(并且仍然创建tmp表并且排序占用了80%的时间)并且查看截断屏幕截图时,大多数时间都会丢失将临时表复制到光盘。这就是差异的来源。我的表只有这个查询所需的列,可能我的随机字符串不像你的那么长,而你有更多的列,你选择所有列,只排序少数。所以你的临时表不适合内存,显然在光盘上做事情要慢得多。

所以你的主要关注点应该是增加缓冲区大小以适应你的大选择或限制列数来选择你可能不需要那么多。

答案 1 :(得分:0)

订单的含义是什么?在这种情况下,在多个变量中使用它是没有意义的。 为什么不一个人订购呢? 您可能遇到数据库设计规范化问题,您熟悉它吗?