查询-
SELECT s.id,
GROUP_CONCAT(s.song_title SEPARATOR ', ') AS titles,
GROUP_CONCAT(a.artist_name SEPARATOR ', ') AS artists,
GROUP_CONCAT(al.album_title SEPARATOR ', ') AS albums,
GROUP_CONCAT(s.release_date SEPARATOR ', ') AS release_dates,
GROUP_CONCAT(sam.role SEPARATOR ', ') AS roles
FROM songs s
INNER JOIN song_artist_mappings sam ON sam.song_id = s.id
INNER JOIN artists a ON sam.artist_id = a.id
INNER JOIN album_track_mappings atm ON atm.song_id = s.id
INNER JOIN albums al on al.id = atm.album_id
GROUP BY s.id
可用索引 -
songs - id
song_artist_mappings - song_id, artist_id
album_track_mappings - song_id, album_id
albums - id
artists - id
该查询返回大约 200 万行(这是歌曲表的大小),并且需要花费很多分钟来执行。有什么办法可以优化吗?
编辑 - 一首歌曲(唯一的歌曲 ID)可以属于多个专辑和艺术家。我必须将所有这些显示为逗号分隔的字符串。少量数据被损坏,其中不同行中的歌曲 ID 具有不同的标题。选择这些标题中的任何一个都可以,所以我想 Song_title 上的 GROUP_CONCAT 是没有必要的。但随后我将不得不选择一个未在 GROUP BY 中列出的非聚合变量。由于数据损坏,我无法对 Song_title 进行分组。
即使我将 LIMIT 5 附加到查询中,在 30GB RAM 计算机上的 InnoDB 上查询也会花费很多分钟。由于 query_cache_size 为 0,因此没有缓存任何查询
编辑 2 - 当我通过 CakePHP 关联获取相同的数据时,查询运行得更快。 CakePHP 将查询拆分为多个查询并按顺序执行它们。
最佳答案
没有。它需要扫描 2M 行,在其他表中查找几百万行,创建一个数百万行的临时表,执行 GROUP BY(可能没有文件排序)最后将 2M 结果行铲到客户端。
好吧,也许...您使用的是哪个引擎?如果您使用 InnoDB,innodb_buffer_pool_size
的值是多少?你有多少内存?该设置应约为可用 RAM 的 70%。当在冷缓存上运行查询时,这没有帮助,因为需要执行大量 I/O。但如果您第二次运行该查询,它的运行速度可能会快 10 倍。
请提供EXPLAIN SELECT ...
,以便我们验证索引是否按预期使用。
降低您的期望 - 200 万行值得花费一些时间。这么多输出到底要做什么?您是否多次需要它?
附录
部分加速是为many:many 表(sam
和atm
)提供更好的索引。特别是,复合查询会更快。 more details .
关于mysql - 具有多个连接、group_concat 和百万行的查询执行缓慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35170061/