【问题标题】:rewriting mysql subquery that is in the from statement重写from语句中的mysql子查询
【发布时间】:2021-11-01 15:26:33
【问题描述】:

这个查询很复杂,但所有单独的部分都可以工作。

查询从用户表中获取与传入的客户端id匹配的所有用户(有一个用户/客户端链接表)

具有挑战性的部分是获取用户已完成哪些 SCORM 课程的详细信息的中间部分(通过或完成的跟踪数据)。但是这个scorm跟踪表并没有scorm对象所在课程的数据,所以我必须计算出课程,课程中的scorm包,scorm包中的sco对象,才能成功确定是否用户已通过课程。

这曾经是在 PHP 中嵌套循环之后的循环内大约 15 个查询,然后在吐出页面/下载 csv 之前作为数组存储在 RAM 中。对于现在运行的用户数量来说,这真的很慢并且超时。

所以我必须找到更好的解决方案。

我已经完成了其他 4 个类似的查询页面——这是最后一个让我失望的页面,因为它是一个总结,即它计算他们完成了多少课程,然后将与他们已经分配的课程数量进行比较,并且给我们一个仪表板。

除了子查询中的 u.id 引用外,它正在工作。

SELECT DISTINCT u.id, u.firstname, u.lastname, u.username,

/* this part of the query gets the number of COMPLETED courses only   */
(SELECT COUNT(CASE WHEN refname=1  THEN 1 ELSE NULL END) AS complete  
FROM
    (SELECT CASE
    /* first check if the number of completions in the scorm tracking table is zero */
    WHEN COUNT(CASE WHEN t1.element = 'cmi.core.lesson_status' AND (t1.value = 'passed' OR t1.value = 'completed') THEN 1 ELSE NULL END) = 0 THEN 0 
    /* then do the original mod */
        WHEN (MOD(COUNT(CASE WHEN t1.element = 'cmi.core.lesson_status' AND (t1.value = 'passed' OR t1.value = 'completed') THEN 1 ELSE NULL END),
            (SELECT COUNT(sc9.id) AS scoes FROM mdl_scorm AS s9 LEFT JOIN mdl_scorm_scoes AS sc9 ON s9.id = sc9.scorm WHERE s9.course = c1.id AND sc9.launch = ''))) > 0 THEN 0
        ELSE 1
    END AS refname
    FROM mdl_user AS u1
    LEFT JOIN mdl_scorm_scoes_track AS t1 ON t1.userid = u1.id
    LEFT JOIN mdl_scorm AS s1  ON s1.id = t1.scormid
    LEFT JOIN mdl_course AS c1 ON c1.id = s1.course
    LEFT JOIN mdl_scorm_scoes AS sc1 ON s1.id = sc1.scorm
    WHERE u1.id = u.id 
    /* **this u.id is part of the OUTERMOST QUERY AND ISN'T SEEN BY THE INNER MOST NEST**    */
    AND sc1.launch = ''    
    GROUP BY c1.id, t1.attempt) AS tblname) 
AS complete,

/* this counts how many courses user has been allocated */
(SELECT COUNT(DISTINCT CONCAT(s2.course, t2.attempt)) AS allocated
FROM mdl_scorm AS s2
LEFT JOIN mdl_scorm_scoes_track AS t2 ON s2.id = t2.scormid
LEFT JOIN mdl_scorm_scoes AS sc2 ON sc2.id = t2.scoid
WHERE t2.userid = u.id),

sfhuc.clientid

FROM mdl_user AS u
LEFT JOIN mdl_sfh_user_client AS sfhuc ON sfhuc.userid = u.id
LEFT JOIN mdl_user_info_data ud_employeeid ON ud_employeeid.userid = u.id AND ud_employeeid.fieldid = 1 
LEFT JOIN mdl_user_info_data ud_jobdescription ON ud_jobdescription.userid = u.id AND ud_jobdescription.fieldid = 3
LEFT JOIN mdl_sfh_client AS sfhc ON sfhc.id = sfhuc.clientid
LEFT JOIN mdl_scorm_scoes_track AS t ON t.userid = u.id

WHERE 1=1
AND u.deleted = 0
AND u.timecreated > 0
AND sfhc.id = 2076441
GROUP BY u.id
ORDER BY u.lastname, u.firstname

【问题讨论】:

    标签: mysql join subquery moodle


    【解决方案1】:
    • 我在FROM(又名“派生表”)中看不到任何子查询。

    • 有些表只引用一列;看看是否可以删除表引用:

        sfhc:  (id)
        t:  (userid)
        sc2:  (id)
        c1:  (id)
        u1:  (id)
      
    • 缩短代码有助于提高可读性:(注意布尔值被视为 1(真)或 0(假),使 SUM 工作。)

        COUNT(CASE WHEN t1.element = 'cmi.core.lesson_status'
            AND  (t1.value = 'passed'
              OR  t1.value = 'completed')
           THEN 1 ELSE NULL END
      
        -->
      
        SUM( t1.element = 'cmi.core.lesson_status' AND
             t1.value IN ('passed', 'completed') )
      
    • CONCAT 是不必要的:

        COUNT(DISTINCT CONCAT(s2.course, t2.attempt))
      
        -->
      
        COUNT(DISTINCT s2.course, t2.attempt)
      
    • 这些似乎完全没用:

        LEFT JOIN  mdl_user_info_data ud_employeeid
              ON  ud_employeeid.userid = u.id
             AND  ud_employeeid.fieldid = 1
      
        LEFT JOIN  mdl_user_info_data ud_jobdescription
              ON  ud_jobdescription.userid = u.id
             AND  ud_jobdescription.fieldid = 3
      
    • 可能的索引:

        sfhuc:  (userid, clientid)
        t2:  (userid, scoid, scormid, attempt)
        t1:  (attempt, scormid, userid, value, element)
        mdl_scorm_scoes:  (launch, scorm)
      

    这些都不一定能“解决”您的问题,但主要指向需要调查或重新思考的领域。

    【讨论】:

    • 非常感谢这些建议。其中一些,尤其是布尔值周围的缩短代码,以及 concat 删除是正确的。其他人是我的错,因为我为了可读性而截断了查询(是的 - 它确实比那更长!)我到了那里!
    猜你喜欢
    • 2012-08-28
    • 1970-01-01
    • 1970-01-01
    • 2015-06-29
    • 1970-01-01
    • 1970-01-01
    • 2021-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多