【问题标题】:How can I speed up my Moodle mysql query with multiple self joins and index如何使用多个自连接和索引加速我的 Moodle mysql 查询
【发布时间】:2018-05-22 20:13:57
【问题描述】:

我创建了一个包含多个连接的查询,用于从多个表中获取数据。对于 5000 多条记录,它的工作速度非常慢。我已经检查并为查询中使用的每个表正确设置了索引。我尝试使用多个选项优化此查询,但它不起作用,我不完全理解 EXPLAIN 或 EXPLAIN EXTENDED 帮助。

=====

查询

EXPLAIN EXTENDED
SELECT @rownum := @rownum + 1 AS id,
       u.id AS userid,
       u.username AS employeeid,
       u.firstname,
       u.lastname,
       u.email AS email,
       u.city AS state,
       c.fullname AS course,
       c.id AS courseid,
       c.fullname AS coursename,
       fi2.data branchid,
       fi3.data branchname,
       fi6.data areaname,
       fi7.data regname,
       fi8.data designation,
       fi9.data department,
       fi10.data zone,
       fi11.data branchcategory,
       fi12.data branchdistrict,
       fi13.data branchstate,
       fi17.data gender,
       fi21.data employeecategory,
       fi22.data persontype,
       fi23.data assignmentstatus,
       fi30.data POSITION,
       fi32.data dateofjoining,
       fi33.data dateofbirth,
       st.scoid,
       st.scormid,
       st.attempt,
       st.value cmistarttime,
       st5.value cmilessonstatus,
       st5.timemodified cmitimemodified,
       st3.value cmitotaltime,
       st2.value cmiscore
FROM (
       SELECT @rownum := 0
     ) r,
     mdl_user u
     JOIN mdl_role_assignments ra ON ra.userid = u.id
     JOIN mdl_context ctx ON ctx.id = ra.contextid
     JOIN mdl_course c ON c.id = ctx.instanceid
     JOIN mdl_scorm s ON s.course = c.id
     JOIN mdl_scorm_scoes_track st ON st.scormid = s.id AND st.userid = u.id
     JOIN mdl_scorm_scoes_track AS st2 ON (u.id = st2.userid AND st2.scormid
       = s.id AND st2.scoid = st.scoid AND st2.attempt = st.attempt)
     JOIN mdl_scorm_scoes_track AS st3 ON (u.id = st3.userid AND st3.scormid
       = s.id AND st3.scoid = st.scoid AND st3.attempt = st.attempt)
     JOIN mdl_scorm_scoes_track AS st5 ON (u.id = st5.userid AND st5.scormid
       = s.id AND st5.scoid = st.scoid AND st5.attempt = st.attempt)
     JOIN mdl_user_info_data AS fi2 ON u.id = fi2.userid
     JOIN mdl_user_info_data AS fi3 ON u.id = fi3.userid
     JOIN mdl_user_info_data AS fi6 ON u.id = fi6.userid
     JOIN mdl_user_info_data AS fi7 ON u.id = fi7.userid
     JOIN mdl_user_info_data AS fi8 ON u.id = fi8.userid
     JOIN mdl_user_info_data AS fi9 ON u.id = fi9.userid
     JOIN mdl_user_info_data AS fi10 ON u.id = fi10.userid
     JOIN mdl_user_info_data AS fi11 ON u.id = fi11.userid
     JOIN mdl_user_info_data AS fi12 ON u.id = fi12.userid
     JOIN mdl_user_info_data AS fi13 ON u.id = fi13.userid
     JOIN mdl_user_info_data AS fi17 ON u.id = fi17.userid
     JOIN mdl_user_info_data AS fi21 ON u.id = fi21.userid
     JOIN mdl_user_info_data AS fi22 ON u.id = fi22.userid
     JOIN mdl_user_info_data AS fi23 ON u.id = fi23.userid
     JOIN mdl_user_info_data AS fi30 ON u.id = fi30.userid
     JOIN mdl_user_info_data AS fi32 ON u.id = fi32.userid
     JOIN mdl_user_info_data AS fi33 ON u.id = fi33.userid
WHERE c.id > 0 AND
      u.id > 0 AND
      u.deleted = 0 AND
      u.suspended = 0 AND
      u.confirmed = 1 AND
      u.id <= 1000 AND
      c.visible = 1 AND
      st.element LIKE '%x.start.time%' AND
      st2.element LIKE '%cmi.core.score.raw%' AND
      st3.element LIKE '%cmi.core.total_time%' AND
      st5.element LIKE '%cmi.core.lesson_status%' AND
      fi2.fieldid = 2 AND
      fi3.fieldid = 3 AND
      fi6.fieldid = 6 AND
      fi7.fieldid = 7 AND
      fi8.fieldid = 8 AND
      fi9.fieldid = 9 AND
      fi10.fieldid = 10 AND
      fi11.fieldid = 11 AND
      fi12.fieldid = 12 AND
      fi13.fieldid = 13 AND
      fi17.fieldid = 17 AND
      fi21.fieldid = 21 AND
      fi22.fieldid = 22 AND
      fi23.fieldid = 23 AND
      fi30.fieldid = 30 AND
      fi32.fieldid = 32 AND
      fi33.fieldid = 33 AND
      ra.roleid = 5 AND
      ctx.contextlevel = 50

===========================

mdl_scorm_scoes_track 表

mdl_scorm_scoes_track table

【问题讨论】:

  • 也许这个问题更适合codereview.stackexchange.com,这里似乎有点离题或宽泛。
  • 很高兴您提供了解释,但我们也需要基础知识。见:Why should I provide an MCVE for what seems to me to be a very simple SQL query? - 你在那里编辑了一些文字吗?这很难说,但如果你有的话也无济于事。
  • 我想分享其他详细信息,例如您是否想查看表结构或其他详细信息。实际上,我之前没有使用 EXPLAIN 并尝试了解它到底指向我的位置。
  • 请提供SHOW CREATE TABLE mdl_scorm_scoes_track -- 该表的“行”数似乎最多。
  • 它是否以 same 方式多次加入 mdl_scorm_scoes_track?这可能是个大问题。

标签: mysql performance query-performance self-join query-tuning


【解决方案1】:

是的,您的假设是正确的。以下是我的轻量级查询。这是 4 路自连接,但具有不同的元素。这是标准表,存储了 14,00,000 多条记录,因此我很难更改表结构或插入查询。

SELECT DISTINCT st1.* FROM mdl_scorm_scoes_track st1
JOIN mdl_scorm_scoes_track st2 ON st1.userid = st2.userid AND st1.scormid = st2.scormid AND st1.scoid = st2.scoid AND st1.attempt = st2.attempt
JOIN mdl_scorm_scoes_track st3 ON st1.userid = st3.userid AND st1.scormid = st3.scormid AND st1.scoid = st3.scoid AND st1.attempt = st3.attempt
JOIN mdl_scorm_scoes_track st4 ON st1.userid = st4.userid AND st1.scormid = st4.scormid AND st1.scoid = st4.scoid AND st1.attempt = st4.attempt
AND st1.element = 'x.start.time' 
AND st2.element = 'cmi.core.score.raw'
AND st3.element = 'cmi.core.total_time'
AND st4.element = 'cmi.core.lesson_status' AND st1.userid <= 10
GROUP BY st1.userid, st1.scormid, st1.scoid, st1.attempt

我也尝试了您建议的方法,但没有帮助。请检查并让我知道我的查询是否有任何问题

SELECT DISTINCT st1.* FROM mdl_scorm_scoes_track st1
JOIN mdl_scorm_scoes_track st2 ON st1.userid = st2.userid AND st1.scormid = st2.scormid AND st1.scoid = st2.scoid AND st1.attempt = st2.attempt
JOIN mdl_scorm_scoes_track st3 ON st1.userid = st3.userid AND st1.scormid = st3.scormid AND st1.scoid = st3.scoid AND st1.attempt = st3.attempt
JOIN mdl_scorm_scoes_track st4 ON st1.userid = st4.userid AND st1.scormid = st4.scormid AND st1.scoid = st4.scoid AND st1.attempt = st4.attempt
AND st1.element = 'x.start.time' 
AND st2.element = 'cmi.core.score.raw'
AND st3.element = 'cmi.core.total_time'
AND st4.element = 'cmi.core.lesson_status' AND st1.userid <= 10
GROUP BY st1.userid, st1.scormid, st1.scoid, st1.attempt
HAVING COUNT(*) = (
  SELECT COUNT(*) FROM mdl_scorm_scoes_track st5
  WHERE st1.userid = st5.userid AND st1.scormid = st5.scormid AND st1.scoid = st5.scoid AND st1.attempt = st5.attempt AND st5.element = 'x.start.time' 
)

【讨论】:

    【解决方案2】:

    您的 4-way self-join 的目的似乎粗略地说是识别 4 行,这些行涉及相同的 userid-scormid-scoid-attempt 但具有 4 个不同的元素。这是获得包含 4 个元素的 4 元组的昂贵方法。 (此外,这 5 列形成一个唯一键。)阅读关系除法,它查找具有与另一个表中的所有子行值一起出现的子行值的行,并用 SQL 表达它。例如,您希望每个 4 元组的组具有不同的元素计数 = 4,其中元素在 4 个值中。

    【讨论】:

      猜你喜欢
      • 2014-03-17
      • 2021-12-20
      • 1970-01-01
      • 1970-01-01
      • 2018-04-21
      • 1970-01-01
      • 2013-07-27
      • 2014-03-01
      • 2018-11-30
      相关资源
      最近更新 更多