无法优化查询

问题描述 投票:-3回答:1
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

Explanation and goal

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

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

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

How the current query works

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

然后,@sum_groupingsum_grouping用于将尝试分成会话和休息。 @sum_grouping只有在尝试超过20分钟(即休息)时才会增加,并且总是增加2.但是,sum_grouping被设置为比那个“休息”小1的值。如果尝试的时间少于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)仅强制返回“当前会话”。

OUTPUT OF 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
mysql query-optimization
1个回答
1
投票

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

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

我看到很多语法错误。

从MyISAM移至InnoDB。

INDEX(a, b)处理你需要INDEX(a)的情况,所以DROP后者。

© www.soinside.com 2019 - 2024. All rights reserved.