我觉得以下查询太慢了:
(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
的操作。
答案 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)
订单的含义是什么?在这种情况下,在多个变量中使用它是没有意义的。 为什么不一个人订购呢? 您可能遇到数据库设计规范化问题,您熟悉它吗?