无法优化查询

时间:2018-02-22 17:51:38

标签: mysql query-optimization

SELECT MIN(classification) AS classification
    ,MIN(START) AS START
    ,MAX(next_start) AS END
    ,SUM(duration) AS seconds
FROM (  SELECT *
            , CASE WHEN (duration < 20*60) THEN CASE WHEN (duration = -1) THEN 'current_session' ELSE 'session' END
              ELSE 'break' 
              END AS classification
            , CASE WHEN (duration > 20*60) THEN ((@sum_grouping := @sum_grouping +2)-1) 
              ELSE @sum_grouping 
              END AS sum_grouping
        FROM (  SELECT *
                    , CASE WHEN next_start IS NOT NULL THEN TIMESTAMPDIFF(SECOND, START, next_start) ELSE -1 END AS duration
                FROM (  SELECT id, studentId, START 
                            , (SELECT MIN(START) 
                               FROM attempt AS sub 
                               WHERE sub.studentId = main.studentId 
                               AND sub.start > main.start
                              ) AS next_start
                        FROM attempt AS main
                        WHERE main.studentId = 605
                        ORDER BY START
                    ) AS t1
            ) AS t2
        WHERE duration != 0
    ) AS t3
GROUP BY sum_grouping
ORDER BY START DESC, END DESC

解释和目标

attempt表记录了学生在会话期间尝试某些活动。如果两次尝试间隔不到20分钟,我们认为这些尝试是相同的会话。如果他们相隔超过20分钟,我们认为他们休息了一段时间。

我对此查询的目标是采取所有尝试并将其压缩在会话和中断列表中,包括每个会话的开始时间,结束时间(定义为后续会话的开始),以及会议有多长。 classification是会话,休息还是当前会话。

上面的查询完成了所有这些,但速度太慢了。如何提高性能?

当前查询的工作原理

最里面的查询选择尝试的开始时间和后续尝试的开始时间,以及这些值之间的持续时间。

然后,@sum_groupingsum_grouping用于将尝试分成会话和休息时间。 @sum_grouping仅在尝试超过20分钟(即中断)时才会增加,并且总是增加2.但是,sum_grouping设置为小于1的值{1}}那&#34;打破&#34;。如果尝试的时间少于20分钟,则使用当前的@sum_grouping值,而不进行修改。结果,所有中断都是不同的奇数值,并且所有会话(无论是1次还是多次尝试)最终都是不同的偶数。这允许GROUP BY部分正确地将尝试分为会话和休息。

示例:

Attempt type @sum_grouping sum_grouping
non-break                0            0
non-break                0            0
break                    2            1
break                    4            3
non-break                4            4
break                    6            5

如您所见,所有中断将按sum_grouping分别用不同的奇数值分组,所有非中断将被组合在一起作为具有偶数值的会话。

MIN(classification)只是强制&#34;当前会话&#34;两个&#34;会话&#34;和&#34;当前会议&#34;存在于分组的行中。

输出SHOW CREATE TABLE attempt

CREATE TABLE attempt (
  id int(11) NOT NULL AUTO_INCREMENT,
  caseId int(11) NOT NULL DEFAULT '0',
  eventId int(11) NOT NULL DEFAULT '0',
  studentId int(11) NOT NULL DEFAULT '0',
  activeUuid char(36) NOT NULL,
  start timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  end timestamp NULL DEFAULT NULL,
  outcome float DEFAULT NULL,
  response varchar(5000) NOT NULL DEFAULT '',
  PRIMARY KEY id),
  KEY activeUuid activeUuid),
  KEY caseId caseId,activeUuid),
  KEY end end),
  KEY start start),
  KEY studentId studentId),
  KEY attempt_idx_studentid_stat_id studentId,start,id),
  KEY attempt_idx_studentid_stat studentId,start
) ENGINE=MyISAM AUTO_INCREMENT=298382 DEFAULT CHARSET=latin1

1 个答案:

答案 0 :(得分:1)

(这不是一个正确的答案,但无论如何都要进行。)

尽量不要嵌套'派生'表。

我看到很多语法错误。

从MyISAM移至InnoDB。

INDEX(a, b)处理您需要INDEX(a)的情况,因此DROP处理后者。