具有多个连接、group_concat 和百万行的查询执行缓慢

Query with multiple joins, group_concat and million rows executes slowly

查询-

    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

查询 returns ~200 万行(这是歌曲的大小 table)并且执行需要很多分钟。有什么办法可以优化吗?

编辑 - 一首歌曲(唯一歌曲 ID)可以属于多个专辑和艺术家。我必须将所有这些显示为逗号分隔的字符串。少量数据已损坏,其中不同行中的歌曲 ID 具有不同的标题。选择任何这些标题都可以,所以我想 GROUP_CONCAT on song_title 是没有必要的。但是然后我将不得不 SELECT 一个未在 GROUP BY 中列出的非聚合变量。由于数据损坏,我无法在 song_title.

上分组

即使我将 LIMIT 5 附加到查询中,在 30GB RAM 机器上的 InnoDB 查询也需要很多分钟。没有查询被缓存,因为 query_cache_size 是 0

编辑 2 - 当我通过 CakePHP 关联获取相同数据时,查询运行得更快。 CakePHP 将查询拆分为多个查询并按顺序执行。

EXPLAIN SELECT

没有。它需要扫描 2M 行,在其他 table 中查找几百万行,创建一个多百万行的 tmp table,执行 GROUP BY(可能没有 filesort) 最后将 2M 结果行铲到客户端。

嗯,也许...您使用的是哪个引擎?如果您使用的是 InnoDB,那么 innodb_buffer_pool_size 的值是多少?你有多少内存?该设置应约为 可用 RAM 的 70%。当 运行 在冷缓存上查询时,这无济于事,因为有很多 I/O 要做。但是,如果您 运行 第二次查询,它可能 运行 快 10 倍。

请提供 EXPLAIN SELECT ... 以便我们验证索引是否按预期使用。

降低您的期望 -- 200 万行值得花一些时间。你到底要用那么多输出做什么?而且你需要它不止一次吗?

附录

部分加速是为 many:many table 提供更好的索引(samatm)。特别是,复合查询会更快。 more details.