是什么让“EXPLAIN”中的行数很少的查询变慢?
What makes a query slow with very few rows in `EXPLAIN`?
我的查询跨索引良好的 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说明:
Table # Rows
homework 200M
student_homework_assn 25M
class_student_assn 2k
class 3k
接下来我应该去哪里查看以减少此查询的 运行 时间?
您说的是索引良好的联接,但我认为根据我从解释和键中得到的信息,这是不准确的。您的键似乎是未优化的单列索引。例如,使用复合键(col1、col2、col3)会有所帮助。
我用别名重写了你的查询以简化一些。还为我自己格式化,以便直观地看到 table 之间的明确关系。我还将 class 状态移动到 JOIN 组件到 class table.
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 上使用以下综合索引,以及为什么...
table: Homework
index: (grade, homework_date, id) or (homework_date, grade, id)
成绩和家庭作业可用于分别按特定日期和成绩优化 WHERE 子句...但是,它还包括用于加入学生家庭作业协会的 ID table。这样,数据库就不必查询页面级别的每条记录来确定哪些记录满足最低标准。该 ID 也包含在加入 student_homework_assn table.
的下一级
table: Student_Homework_Assn
index: (homework_id, student_id)
家庭作业 ID 匹配上一个 table 家庭作业,但是下一级的学生 ID 也...
table: class_student_assn
index: (student_id, class_id )
相似,student匹配上一个,class匹配下一个
table: class
index: (id, class_status_id )
终于 class 和它的状态。
我会对这个的结果感兴趣...并且根据您的查询,我有另一种选择
我的查询跨索引良好的 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说明:
Table # Rows
homework 200M
student_homework_assn 25M
class_student_assn 2k
class 3k
接下来我应该去哪里查看以减少此查询的 运行 时间?
您说的是索引良好的联接,但我认为根据我从解释和键中得到的信息,这是不准确的。您的键似乎是未优化的单列索引。例如,使用复合键(col1、col2、col3)会有所帮助。
我用别名重写了你的查询以简化一些。还为我自己格式化,以便直观地看到 table 之间的明确关系。我还将 class 状态移动到 JOIN 组件到 class table.
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 上使用以下综合索引,以及为什么...
table: Homework
index: (grade, homework_date, id) or (homework_date, grade, id)
成绩和家庭作业可用于分别按特定日期和成绩优化 WHERE 子句...但是,它还包括用于加入学生家庭作业协会的 ID table。这样,数据库就不必查询页面级别的每条记录来确定哪些记录满足最低标准。该 ID 也包含在加入 student_homework_assn table.
的下一级table: Student_Homework_Assn
index: (homework_id, student_id)
家庭作业 ID 匹配上一个 table 家庭作业,但是下一级的学生 ID 也...
table: class_student_assn
index: (student_id, class_id )
相似,student匹配上一个,class匹配下一个
table: class
index: (id, class_status_id )
终于 class 和它的状态。
我会对这个的结果感兴趣...并且根据您的查询,我有另一种选择