优化使用三个表来排序列表的查询

时间:2015-04-21 23:59:24

标签: php mysql sql eloquent left-join

所以我的查询完全符合预期,但需要大量优化。我正在使用软件来跟踪我网站上的加载时间,并且我网站上97.8%的加载时间是这一功能的结果。所以在进入查询之前先解释一下我的数据库。

首先,我有一张电影桌,一张比赛表和一张投票表。电影可以参加许多比赛,比赛有很多电影,因为这是一个多对多的关系,我们有一个数据透视表来显示他们的关系(电影竞赛)当加载比赛页面时,这些电影需要按照他们的投票顺序(大多数)投票在顶部。最少在底部。)

现在在下面的查询中,您可以看到我正在做的事情,从电影竞赛表中获取与当前比赛ID $ competition-> id匹配的电影,然后我按照该电影的总票数进行排序。就像我说的那样有效,但效率很高,但我想不出另一种方法。

$films =  DB::select( DB::raw("SELECT f.*, COUNT(v.value) AS totalVotes
    FROM filmCompetition AS fc
    JOIN films AS f ON f.id = fc.filmId AND fc.competitionId = '$competition->id'
    LEFT JOIN votes AS v ON f.id = v.filmId AND v.competitionId = '$competition->id'
    GROUP BY f.id
    ORDER BY totalVotes DESC
    ") );

2 个答案:

答案 0 :(得分:1)

对于此查询,您需要filmCompetition(competitionId, filmId)films(id)和投票(filmId,competitionId)的索引。

但是,编写这样的查询可能更有效:

SELECT f.*,
       (SELECT COUNT(v.value)
        FROM votes v
        WHERE v.filmId = f.id and v.competitionId = '$competition->id'
       ) AS totalVotes
FROM films f
WHERE EXISTS (SELECT 1
              FROM FilmCompetition fc
              WHERE fc.FilmId = f.Filmid AND 
                    fc.competitionId = '$competition->id'
             )
ORDER BY TotalVotes DESC

这样可以保存外部聚合,这应该是性能上的提升。对于此版本,索引为FilmCompetition(FilmId, CompetitionId)Votes(FilmId, CompetitionId)

答案 1 :(得分:0)

我实际上最终使用的解决方案有点不同,但自从戈登回答了这个问题后,我将他标记为正确答案。

我的解决方案 为了实际修复这个问题,我做了一个稍微不同的方法,而不是尝试在SQL中完成所有这些操作,我分别完成了三个查询,然后在PHP中将它们连接在一起。虽然在我的情况下,这可能会慢一点,我的原始方式需要大约15秒,这样做Gordons的方式大约需要7秒,而这样做我的新方式需要大约600毫秒。