我有三张桌子。

一张表格包含大约75,000行的提交
一张表格包含提交评分,并且只有一张表包含提交=>竞争映射,而对于我的测试数据,该表也有大约75,000行。

我想做的是


  在一轮比赛中获得前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


Submitting_submissions

CREATE TABLE `submission_submissions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `account_id` int(11) NOT NULL,
  `title` varchar(255) NOT NULL,
  `description` varchar(255) DEFAULT NULL,
  `genre` int(11) NOT NULL,
  `goals` text,
  `submission` text NOT NULL,
  `date_created` datetime DEFAULT NULL,
  `date_modified` datetime DEFAULT NULL,
  `date_deleted` datetime DEFAULT NULL,
  `cover_image` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `genre` (`genre`),
  KEY `account_id` (`account_id`),
  KEY `date_created` (`date_created`)
) ENGINE=InnoDB AUTO_INCREMENT=115037 DEFAULT CHARSET=latin1;


Submitting_ratings

CREATE TABLE `submission_ratings` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `account_id` int(11) NOT NULL,
  `submission_id` int(11) NOT NULL,
  `stars` tinyint(1) NOT NULL,
  `date_created` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `submission_id` (`submission_id`),
  KEY `account_id` (`account_id`),
  KEY `stars` (`stars`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1;


比赛提交

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)

最佳答案

假设实际上您不会对未分级提交感兴趣,并且对于给定的匹配项和top_round,给定的提交仅具有一个competition_submissions条目,我建议:

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


(如果对于给定的匹配项和top_round,每个提交中有多个competition_submissions条目,则可以将GROUP BY子句重新添加到主查询中。)

如果您确实希望查看未评级的提交,则可以将该查询的结果合并到LEFT JOIN ... WHERE NULL查询中。

10-05 19:37