我得到了一个查询,它给出了我想要的结果,但执行起来却耗费了很长时间。有人能给我一些建议来加速这个查询吗?
下面是查询:
SELECT StudentDB.studentid,
ClassDB.classID,
ClassDB.class_level,
ClassDB.class_title,
ClassDB.TIME,
ClassDB.teacher,
StudentDB.first_name,
StudentDB.last_name
FROM StudentDB
INNER JOIN AttendanceDB
ON StudentDB.studentid = AttendanceDB.studentid
INNER JOIN ClassDB
ON AttendanceDB.classid = ClassDB.classID
WHERE StudentDB.studentid NOT IN (
SELECT studentID
FROM AttendanceDB
WHERE (
class_time >= '$todaysdate1'
AND class_time < '$tomorrowsdate1'
)
AND (
furikae = '0'
OR furikae = '2'
OR furikae = '1'
)
)
AND DATE (AttendanceDB.class_time) = '$datecheck'
AND AttendanceDB.furikae = '3'
UNION ALL
SELECT StudentDB.studentid,
ClassDB.classID,
ClassDB.class_level,
ClassDB.class_title,
ClassDB.TIME,
ClassDB.teacher,
StudentDB.first_name,
StudentDB.last_name
FROM StudentDB
INNER JOIN RegDB
ON StudentDB.studentID = RegDB.studentid
INNER JOIN ClassDB
ON ClassDB.classID = RegDB.classid
WHERE StudentDB.studentid NOT IN (
SELECT studentID
FROM AttendanceDB
WHERE (
class_time >= '$todaysdate1'
AND class_time < '$tomorrowsdate1'
)
AND (
furikae = '0'
OR furikae = '2'
OR furikae = '1'
)
)
AND ClassDB.day = '$dayofweek'
ORDER BY TIME ASC,
class_title ASC基本上我的数据库结构是这样的:
StudentDB
ClassDB
RegDB
AttendanceDBStudentDB (这个有很多列,其中包含学生的电话号码等数据,这些数据是无关的,我将删除这些列以进行缩写)
studentid int(11) No None AUTO_INCREMENT
first_name text latin1_swedish_ci No None
last_name text latin1_swedish_ci No None
class_level text latin1_swedish_ci No None ClassDB
classID int(11) No None AUTO_INCREMENT
class_title text latin1_swedish_ci No None
class_level text latin1_swedish_ci No None
day text latin1_swedish_ci No None
time time No None
teacher text latin1_swedish_ci No None RegDB
regid int(11) No None AUTO_INCREMENT
classid int(11) No None
studentid int(11) No None AttendanceDB
attendanceID int(11) No None AUTO_INCREMENT
studentid int(11) No None
classid int(11) No None
class_time timestamp on update CURRENT_TIMESTAMP No CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
furikae int(11) No None RegDB将StudentDB链接到ClassDB,该学生参加哪个课程。AttendanceDB记录哪些学生实际参加了哪个课程,以及记录哪些学生将加入(将来)不是他们的常规课程的课程。
我想对这个选择做的是获得所有注册到某个班级或有不定期预约的学生,减去已经标记为当天签到的学生。
正如我所说的,这会输出正确的结果,但速度非常慢。
发布于 2015-12-18 21:24:17
让我们将联合的第一部分称为query1,将联合的第二部分称为query2。现在在query1 AttendenceDB中是中间表b/n studentDB和ClassDB,在query2 RegDB中是中间表b/n studentDB和ClassDB。其他条件也是一样的。如果我们先将RegDB和AttendenceDB的条件合并,然后将合并的结果与studentDB和ClassDB连接起来,就可以避免不必要的连接。
发布于 2015-12-18 23:25:40
更详细的问题,我可以稍后使用解决方案进行编辑。为了更好地理解您的数据结构,让我为自己(以及其他人)澄清以下几点。
StudentDB -显而易见。每名学生一份记录。
ClassDB -提供的所有可能的课程的列表,并且可以具有相同课程的多个实例,例如编程101,但可以在不同的日期、不同的学期、谁在教授特定的实例等。
RegDB -列出学生注册特定课程的所有条目。因此,学生: class的每条记录都是1:1。
AttendanceDB -每个学生的出勤率:班级:日期。我假设考勤表也有考勤的类ID。如果一个学生有5个班级,他们可能会出现在1-3班,提前离开去上4-5班。如果这是公立学校K-12,一个学生提早离开去看医生,你知道他们在那里上了一些课,但不是全部。如果大学,同样,不能保证他们在给定的一天有多节课,但可以上一节课,但不一定是所有的课。
因此,从这个角度来看,我会这样看待它。首先,给我所有符合相关日期(ClassDB)的类。然后转到注册表,看看谁注册了它,然后转到注册的学生。这些将始终是有效的连接。在此基础上,根据细微差别/状态对出席表进行条件连接
If将有助于查看表的结构,即使是为了确认查询所关联/所需的列。我希望类表具有它可能适用的日期范围……如2015年9月1日至2015年12月18日的课程。
因此,我的临时解决方案。我添加了Furikae字段,这样您就可以获得所有内容,并将结果作为此查询的基线考虑因素。
SELECT
S.studentid,
C.classID,
C.class_level,
C.class_title,
C.TIME,
C.teacher,
S.first_name,
S.last_name,
ADB.furikae
FROM
ClassDB C
JOIN RegDB R
on C.ClassID = R.ClassID
JOIN StudentDB S
ON R.studentid = S.studentID
LEFT JOIN AttendanceDB ADB
on C.ClassID = ADB.ClassID
AND S.StudentID = ADB.StudentID
AND ADB.class_time >= '$todaysdate1'
AND ADB.class_time < '$tomorrowsdate1'
WHERE
'$datecheck' BETWEEN C.StartDate and C.EndDate
AND C.day = '$dayofweek'
AND ( ADB.Furikae IS NULL
OR ADB.Furikae = '3' )现在,您所要做的就是根据Furikae字段应用一个附加的AND子句。我放了一个这样的条件的例子,因为我不知道这个Furikae状态字段的用途。此外,出勤确认是特别寻找当前日期的基础,因为学生可以在一周前参加,但不是基于“今天”的出勤。
对于索引,我建议使用以下方法。同样,不知道类表是否有from/to date考虑
table indexed on
ClassDB (classID, StartDate, EndDate )
RegDB (classID, StudentID )
StudentDB (StudentID) -- would expect as it is primary key
AttendanceDB (classID, StudentID, class_time, Furikae )https://stackoverflow.com/questions/34356206
复制相似问题