mysql join按第三个表的平均值排序的结果?

mysql join按第三个表的平均值排序的结果?,mysql,sorting,join,Mysql,Sorting,Join,我有三张桌子 一个表包含约75000行的提交内容 一个表包含提交评级,只有competition映射,对于我的测试数据,还有大约75000行 我想做的是 在一轮比赛中获得前50名的参赛作品。 排名靠前的是最高的平均评分,其次是最高的票数 这是我正在使用的有效查询,但问题是它需要超过45秒才能完成!我分析了查询(底部的结果),瓶颈是将数据复制到tmp表中,然后对其进行排序,因此如何加快速度 SELECT `submission_submissions`.* FROM `submissio

我有三张桌子

一个表包含约75000行的提交内容
一个表包含提交评级,只有<10行
一个表包含submission=>competition映射,对于我的测试数据,还有大约75000行

我想做的是

在一轮比赛中获得前50名的参赛作品。 排名靠前的是最高的平均评分,其次是最高的票数

这是我正在使用的有效查询,但问题是它需要超过45秒才能完成!我分析了查询(底部的结果),瓶颈是将数据复制到tmp表中,然后对其进行排序,因此如何加快速度

 SELECT `submission_submissions`.* 
   FROM `submission_submissions`
   JOIN `competition_submissions` 
     ON `competition_submissions`.`submission_id` = `submission_submissions`.`id`
LEFT JOIN `submission_ratings` 
     ON `submission_submissions`.`id` = `submission_ratings`.`submission_id`
  WHERE `top_round` =  1 
    AND `competition_id` =  '2'
    AND `submission_submissions`.`date_deleted` IS NULL
GROUP BY submission_submissions.id
ORDER BY AVG(submission_ratings.`stars`) DESC, 
         COUNT(submission_ratings.`id`) DESC
  LIMIT 50
意见书 投稿及评分 参赛作品 显示配置文件结果(按持续时间排序) 说明
假设事实上,您对未评分的参赛作品不感兴趣,并且给定的参赛作品只有一个
竞赛提交作品
参赛作品和顶级比赛,我建议:

SELECT s.* 
FROM (SELECT `submission_id`, 
             AVG(`stars`) AvgStars, 
             COUNT(`id`) CountId
      FROM `submission_ratings` 
      GROUP BY `submission_id`
      ORDER BY AVG(`stars`) DESC, COUNT(`id`) DESC
      LIMIT 50) r
JOIN `submission_submissions` s
  ON r.`submission_id` = s.`id` AND
     s.`date_deleted` IS NULL
JOIN `competition_submissions` c
  ON c.`submission_id` = s.`id` AND 
     c.`top_round` =  1 AND
     c.`competition_id` = '2'
ORDER BY r.AvgStars DESC, 
         r.CountId DESC
(如果对于给定的比赛和第一轮比赛,每次提交的参赛作品都有多个
参赛作品
条目,则可以将GROUP BY子句添加回主查询。)


如果您确实希望查看未分级的提交,可以将此查询的结果合并到左联接。。。其中为空查询。

在MySql上有一个简单的技巧,可以帮助避免在这样的查询中复制/排序大型临时表(限制为X)。

只需避免
选择*
,这会将所有列复制到临时表中,然后对这个巨大的表进行排序,最后,查询只从这个巨大的表中获取50条记录(50/70000=0,07%)。

仅选择确实需要执行排序和限制的列,然后仅按id为选定的50条记录连接缺少的列

select ss.*
from submission_submissions ss
join (
            SELECT `submission_submissions`.id, 
                    AVG(submission_ratings.`stars`) stars,
                    COUNT(submission_ratings.`id`) cnt
               FROM `submission_submissions`
               JOIN `competition_submissions` 
                 ON `competition_submissions`.`submission_id` = `submission_submissions`.`id`
            LEFT JOIN `submission_ratings` 
                 ON `submission_submissions`.`id` = `submission_ratings`.`submission_id`
              WHERE `top_round` =  1 
                AND `competition_id` =  '2'
                AND `submission_submissions`.`date_deleted` IS NULL
            GROUP BY submission_submissions.id
            ORDER BY AVG(submission_ratings.`stars`) DESC, 
                     COUNT(submission_ratings.`id`) DESC
              LIMIT 50
) xx
ON ss.id = xx.id
ORDER BY xx.stars DESC, 
         xx.cnt DESC; 

“一个表包含提交评级,并且只有<10行”-肯定有些错误?你不仅在评分表中包括了选择标准,而且还从评分表中按平均星级和总评分进行排序,然后用评分表确定前50名提交的作品。这是我的测试数据,我还没有将该表填满,所以目前它只有<10行,不管怎样,因为我使用了左连接,所以应该包括没有评分的结果…您想如何对没有评分的结果进行排名?您现有的
order by
仅与评级表中的聚合值相关,但与真实数据相比,评级与提交的比率更可能达到3:1左右。无评分的结果可在有评分的结果后列出;事实上,我们真的不在乎没有评级的结果;我们甚至可以在某个时候通过标准连接过滤掉它们(更正我的原始评论:我后来注意到WHERE子句标准是关于提交和竞争提交的值,而不是评级值)
CREATE TABLE `competition_submissions` (
  `competition_id` int(11) NOT NULL,
  `submission_id` int(11) NOT NULL,
  `top_round` int(11) DEFAULT '1',
  PRIMARY KEY (`submission_id`),
  KEY `competition_id` (`competition_id`),
  KEY `top_round` (`top_round`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
state                 duration (summed) in sec percentage
Copying to tmp table  33.15621                 68.46924
Sorting result        11.83148                 24.43260
removing tmp table     3.06054                  6.32017
Sending data           0.37560                  0.77563
... insignificant amounts removed ...
Total                  48.42497               100.00000
id  select_type  table                    type         possible_keys                     key                       key_len  ref                                              rows   Extra                                                                                                 
1   SIMPLE       competition_submissions  index_merge  PRIMARY,competition_id,top_round  competition_id,top_round  4,5                                                       18596  Using intersect(competition_id,top_round); Using where; Using index; Using temporary; Using filesort  
1   SIMPLE       submission_submissions   eq_ref       PRIMARY                           PRIMARY                   4        inkstakes.competition_submissions.submission_id  1      Using where                                                                                           
1   SIMPLE       submission_ratings       ALL          submission_id                                                                                                         5      Using where; Using join buffer (flat, BNL join)                                                       
SELECT s.* 
FROM (SELECT `submission_id`, 
             AVG(`stars`) AvgStars, 
             COUNT(`id`) CountId
      FROM `submission_ratings` 
      GROUP BY `submission_id`
      ORDER BY AVG(`stars`) DESC, COUNT(`id`) DESC
      LIMIT 50) r
JOIN `submission_submissions` s
  ON r.`submission_id` = s.`id` AND
     s.`date_deleted` IS NULL
JOIN `competition_submissions` c
  ON c.`submission_id` = s.`id` AND 
     c.`top_round` =  1 AND
     c.`competition_id` = '2'
ORDER BY r.AvgStars DESC, 
         r.CountId DESC
select ss.*
from submission_submissions ss
join (
            SELECT `submission_submissions`.id, 
                    AVG(submission_ratings.`stars`) stars,
                    COUNT(submission_ratings.`id`) cnt
               FROM `submission_submissions`
               JOIN `competition_submissions` 
                 ON `competition_submissions`.`submission_id` = `submission_submissions`.`id`
            LEFT JOIN `submission_ratings` 
                 ON `submission_submissions`.`id` = `submission_ratings`.`submission_id`
              WHERE `top_round` =  1 
                AND `competition_id` =  '2'
                AND `submission_submissions`.`date_deleted` IS NULL
            GROUP BY submission_submissions.id
            ORDER BY AVG(submission_ratings.`stars`) DESC, 
                     COUNT(submission_ratings.`id`) DESC
              LIMIT 50
) xx
ON ss.id = xx.id
ORDER BY xx.stars DESC, 
         xx.cnt DESC;