使用多个子查询加速mysql查询

使用多个子查询加速mysql查询,mysql,optimization,subquery,Mysql,Optimization,Subquery,我想知道是否有一种方法可以加速由多个子查询排序的mysql查询 在与音乐相关的网站上,用户可以喜欢艺术家、歌曲、专辑等不同的东西。这些“喜欢”都存储在同一个表中。现在我想显示一个艺术家列表,按用户朋友和所有用户的“喜欢”数量排序。我想展示所有的艺术家,还有那些根本不喜欢的艺术家 我有以下疑问: SELECT `artists`.*, // friend likes (SELECT COUNT(*) FROM `likes` WHERE like_type

我想知道是否有一种方法可以加速由多个子查询排序的mysql查询

在与音乐相关的网站上,用户可以喜欢艺术家、歌曲、专辑等不同的东西。这些“喜欢”都存储在同一个表中。现在我想显示一个艺术家列表,按用户朋友和所有用户的“喜欢”数量排序。我想展示所有的艺术家,还有那些根本不喜欢的艺术家

我有以下疑问:

SELECT `artists`.*, 

    // friend likes
    (SELECT COUNT(*)
     FROM `likes`
     WHERE like_type = 'artist'
     AND like_id = artists.id
     AND user_id IN (1,2,3,4, etc) // ids of friends
     GROUP BY like_id
    ) AS `friend_likes`, 

    // all likes
    (SELECT COUNT(*)
     FROM `likes`
     WHERE like_type = 'artist'
     AND like_id = artists.id
     GROUP BY like_id
    ) AS `all_likes`

FROM artists
ORDER BY 
    friend_likes DESC, 
    all_likes DESC, 
    artists.name ASC
对于包含2000行的artist表,查询需要±1.5秒。随着桌子越来越大,恐怕这需要越来越长的时间。我尝试使用joinby,但似乎无法实现这一点,因为子查询包含WHERE语句


任何方向正确的想法都将不胜感激

你需要把它分解一下,看看时间会到哪里去。你完全正确,2000行上的1.5秒不能很好地扩展。我想您需要查看索引和外键关系。逐个查询每个计数/组,以使它们尽可能地优化,然后重新组合。

您需要将其分解一点,以了解时间的推移。你完全正确,2000行上的1.5秒不能很好地扩展。我想您需要查看索引和外键关系。逐个查询查看每个计数/组,以使它们尽可能优化,然后重新组合。

尝试使用
JOIN
s而不是子查询:

SELECT
  artists.*, -- do you really need all this?
  count(user_id) AS all_likes,
  sum(user_id IN (1, 2, 3, 4)) AS friend_likes
FROM artists a
LEFT JOIN likes l
  ON l.like_type = 'artist' AND l.like_id = a.id
GROUP BY a.id
ORDER BY 
  friend_likes DESC, 
  all_likes DESC, 
  artists.name ASC;

如果这不能使查询更快,请尝试添加索引,或者考虑选择更少的字段。

尝试使用<代码>连接< /代码> s,而不是子查询:

SELECT
  artists.*, -- do you really need all this?
  count(user_id) AS all_likes,
  sum(user_id IN (1, 2, 3, 4)) AS friend_likes
FROM artists a
LEFT JOIN likes l
  ON l.like_type = 'artist' AND l.like_id = a.id
GROUP BY a.id
ORDER BY 
  friend_likes DESC, 
  all_likes DESC, 
  artists.name ASC;

如果这并不能使查询更快,请尝试添加索引,或者考虑选择更少的字段。

尝试使用内联IF-()来查询查询,并通过表/联接一次< /P>
SELECT STRAIGHT_JOIN
  artists.*
  , LikeCounts.AllCount
  , LikeCounts.FriendLikeCount
FROM  
  (SELECT
    like_id
    , count(*) AllCount
    , sum( If( User_id in ( 1, 2, 3, 4 ), 1, 0 ) as FriendLikeCount
  FROM
    friend_likes
  WHERE
    like_type = 'artist'
  GROUP BY 
    like_id ) LikeCounts
JOIN artists ON LikeCounts.like_id = artists.id
ORDER BY
  LikeCounts.FriendLikeCount DESC
  , LikeCounts.AllCount DESC
  , artists.name ASC

尝试使用inline IF()向上滚动到查询中,并遍历表/联接一次

SELECT STRAIGHT_JOIN
  artists.*
  , LikeCounts.AllCount
  , LikeCounts.FriendLikeCount
FROM  
  (SELECT
    like_id
    , count(*) AllCount
    , sum( If( User_id in ( 1, 2, 3, 4 ), 1, 0 ) as FriendLikeCount
  FROM
    friend_likes
  WHERE
    like_type = 'artist'
  GROUP BY 
    like_id ) LikeCounts
JOIN artists ON LikeCounts.like_id = artists.id
ORDER BY
  LikeCounts.FriendLikeCount DESC
  , LikeCounts.AllCount DESC
  , artists.name ASC


在其他人之前-将EXPLAIN放在SELECT语句之前会得到什么?是否对艺术家表中的联接列进行了索引?在其他人之前-将EXPLAIN放在SELECT语句之前会得到什么?是否对艺术家表中的联接列进行了索引?恐怕这会有助于提高性能。内部查询优化器可能已经在其环境中尽可能地减少了查询。@d-live:我可以想象优化器已经用联接替换了每个子查询,但它还会将两个子查询放在一起吗?啊哈,是的。我对连接语法和非连接语法进行了评论。是的,您将子查询组合为eather+1是正确的:)@d-live:我在like.like_id字段上添加了一个索引,现在查询运行速度快得多,±0.03秒。当字段可以引用不同表中的不同列时,是否可以向字段添加索引?(专辑id、歌曲id或艺术家id)@Martijn:谢谢你告诉我如何加入!查询现在看起来更整洁,但运行速度非常慢。不带索引字段时为±1.7秒,带索引字段时为±0.06秒,而带索引字段时为±1.5秒和±0秒。03@smek:只是另一个脑电波;您是否制作了类似于_type的枚举?恐怕这将有助于提高性能。内部查询优化器可能已经在其环境中尽可能地减少了查询。@d-live:我可以想象优化器已经用联接替换了每个子查询,但它还会将两个子查询放在一起吗?啊哈,是的。我对连接语法和非连接语法进行了评论。是的,您将子查询组合为eather+1是正确的:)@d-live:我在like.like_id字段上添加了一个索引,现在查询运行速度快得多,±0.03秒。当字段可以引用不同表中的不同列时,是否可以向字段添加索引?(专辑id、歌曲id或艺术家id)@Martijn:谢谢你告诉我如何加入!查询现在看起来更整洁,但运行速度非常慢。不带索引字段时为±1.7秒,带索引字段时为±0.06秒,而带索引字段时为±1.5秒和±0秒。03@smek:只是另一个脑电波;你有没有做过类似于“类型”的枚举?在(1,2,3,4)中可以重写为1到4,将4个测试减少为2。@Johan,是的,但是发帖的人实际上提供的列表可能是1,8,12,38,53,2300。。。我只是发布了一个简单的例子。原来的问题是1,2,3等等。所以两者之间的关系是有意义的。如果列表确实是随机的,那么用户id上的内部联接可能更有序。@Johan,我同意可能的内部联接。。。然而,除非有实质性的目的,否则不应该对其他人的帖子内容进行编辑。仅仅因为您有一个不同的SQL语句样式,就不应该“仅仅因为”这样做。最初输入的方式更容易显示第一个查询与下一个查询的连接关系。。。别管其他人的样式,除非用户没有获得{}的代码格式设置,否则它是完全未格式化的。包含用户ID的列表是随机的。我刚才以1,2,3为例@Johan,您的查询只返回有一个或多个喜欢的艺术家,而不是所有的艺术家。在(1,2,3,4)中可以重写为1到4,将4个测试减少为2。@Johan,是的,但发帖的人实际上提供的列表可能是1、8、12、38、53、2300。。。我只是发布了一个简单的例子。原来的问题是1,2,3等等。所以两者之间的关系是有意义的。如果列表确实是随机的,那么用户id上的内部联接可能更有序。@Johan,我同意可能的内部联接。。。然而,除非有实质性的目的,否则不应该对其他人的帖子内容进行编辑。仅仅因为您有一个不同的SQL语句样式,就不应该“仅仅因为”这样做。最初输入的方式更容易显示第一个查询与下一个查询的连接关系。。。别管其他人的样式,除非用户没有获得{}的代码格式设置