mysql - 是什么让 `EXPLAIN` 中的行很少的查询变慢?

标签 mysql sql query-optimization

我的查询通过索引良好的 JOIN 跨越 4 个表,最多约 500 行。然而,查询通常需要几分钟才能完成。

我错过了什么?

EXPLAIN
SELECT
    homework.id AS homework_id,
    homework.description
FROM homework
JOIN student_homework_assn 
  ON homework.id = student_homework_assn.homework_id
JOIN class_student_assn 
  ON student_homework_assn.student_id = class_student_assn.student_id
JOIN class 
  ON class_student_assn.class_id = class.id
WHERE homework.grade IS NULL
  AND homework.homework_date > DATE_ADD(NOW(), INTERVAL -1 DAY)
  AND class.class_status_id = 2
LIMIT 1000;

*** row 1 ***
          table:  class
           type:  ref
  possible_keys:  PRIMARY,class_status_id,class_multi_1
            key:  class_status_id
        key_len:  4
            ref:  const
           rows:  539
          Extra:  Using index
*** row 2 ***
          table:  class_student_assn
           type:  ref
  possible_keys:  student_id_2,student_id
            key:  student_id_2
        key_len:  4
            ref:  class.id
           rows:  1
          Extra:  Using index
*** row 3 ***
          table:  student_homework_assn
           type:  ref
  possible_keys:  PRIMARY,idx_homework_id,idx_student_id
            key:  idx_student_id
        key_len:  8
            ref:  class_student_assn.student_id
           rows:  262
          Extra:  Using index
*** row 4 ***
          table:  homework
           type:  eq_ref
  possible_keys:  PRIMARY,id,homework_date
            key:  PRIMARY
        key_len:  8
            ref:  student_homework_assn.homework_id
           rows:  1
          Extra:  Using where

简要表说明:

Table                   # Rows
homework                200M
student_homework_assn    25M
class_student_assn        2k
class                     3k

接下来我应该去哪里查看以减少此查询的运行时间?

最佳答案

您说的是索引良好的联接,但我认为根据我从解释和键中得到的信息,这并不准确。您的键似乎是未优化的单列索引。例如,使用复合键(col1、col2、col3)会有所帮助。

我用别名重写了您的查询以简化一些。还为我自己格式化以直观地查看表之间的明确关系。我还将类状态移动到类表的 JOIN 组件。

SELECT
      H.id AS homework_id,
      H.description
   FROM 
      Homework H
         JOIN student_homework_assn SHA
            ON H.id = SHA.homework_id
            JOIN class_student_assn CSA
               ON SHA.student_id = CSA.student_id
               JOIN class C
                  ON CSA.class_id = C.id
                 AND C.class_status_id = 2
   WHERE 
          H.grade IS NULL
      AND H.homework_date > DATE_ADD(NOW(), INTERVAL -1 DAY)
   LIMIT 
      1000;

我会建议在您各自的表上使用以下复合索引以及为什么...

table: Homework        
index: (grade, homework_date, id)   or  (homework_date, grade, id)

成绩和家庭作业可用于分别按特定日期和成绩优化 WHERE 子句...但是,它还包括用于加入学生家庭作业关联表的 ID。这样,数据库就不必查询页面级别的每条记录来确定哪些记录满足最低标准。该 ID 也包含在加入 student_homework_assn 表的下一级中。

table: Student_Homework_Assn  
index: (homework_id, student_id)

作业 ID 与之前的作业表相匹配,但是下一级的学生 ID 也...

table: class_student_assn
index: (student_id, class_id )

类似的,student匹配上一个,class匹配下一个

table: class
index: (id, class_status_id )

最后是类及其状态。

我会对这个的结果感兴趣...并且取决于您的查询,我有另一种选择

关于mysql - 是什么让 `EXPLAIN` 中的行很少的查询变慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32835821/

相关文章:

sql - 如何快速 self 加入(与不同的相同)?

javascript - 使用嵌入的表单集合保存相关 Doctrine 实体时出现 Symfony SQL 错误

sql - 谁能解释一下这个 SQL 查询

php - 如何仅在具有不同行的情况下更新 SQL

python - 无效的 UTF-8 代码序列

MySQL表设计结构用户偏好

sql-server - 为什么这个执行计划中排序运算符的成本如此之高?

php - 合并对象数组中除一个值之外的重复项... php/mysql

PHP - mysql_fetch_assoc() 问题

mysql - Hibernate 将 POST 请求中的 JSON 值错误地映射为 null