使用UNION ALL查询速度慢

时间:2015-12-18 12:55:47

标签: mysql union

我有一个查询,它给了我想要的结果,但需要永远执行。任何人都可以给我任何建议来加快这个问题吗?

以下是查询:

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
AttendanceDB

StudentDB(这个有很多专栏的数据,如学生和电话号码不相关,我会删除以缩写)

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记录哪个学生实际上参加哪个班级,以及记录学生将加入(将来)一个不属于他们常规班级的班级。

我想用这个SELECT做的是让所有注册到班级或有不正常约会的学生,减去那些已经被标记为当天登记的学生。

正如我所说,这会输出正确的结果,但速度极慢。

2 个答案:

答案 0 :(得分:1)

让我们将union的第一部分称为query1,将union的第二部分称为query2。现在在query1中,AttendenceDB是中间表b / n studentDB和ClassDB,在query2中,RegDB是中间表b / n studentDB和ClassDB。和其他条件相同。如果我们首先联合RegDB和AttendenceDB的秒数,然后将这个结果与studentDB和ClassDB结合起来,我们可以避免不必要的加入。

答案 1 :(得分:1)

更多详细问题我稍后可以使用解决方案进行编辑。为了更好地理解您的数据结构,请让我为自己(以及其他任何人)澄清以下内容。

StudentDB - 很明显。每个学生一个记录。

ClassDB - 提供的所有可能类的列表,并且可以具有相同类的多个实例,例如编程101,但可以在不同日期,不同学期,教授特定实例等提供。 / p>

RegDB - 列出学生注册特定课程的所有条目。因此,对于学生来说,每个记录都是1:1。

AttendanceDB - 每位学生的出勤率:上课时间:日期。我会认为考勤表也有出勤的班级ID。如果一个学生有5个班级,他们可能会出现在1-3班,并提前离开4-5班。如果这是公立学校K-12,并且一名学生提前离开参加博士约会,你知道他们在那里参加一些课程,但不是全部。如果大学同样地,不能保证他们在某一天有多个班级,但可以参加一个班级,但不一定是所有班级。

因此,我会以这种方式看待它。首先,给我所有符合相关日期的课程(ClassDB)。然后到注册表中注册谁,然后注册到学生。那些永远是有效的JOIN。由此,基于细微差别/状态

的条件加入到考勤表

如果WOULD有助于查看表的结构,即使缩写为确认查询关联/需要的列。我希望班级表格具有可能适用的日期范围......例如2015年9月1日至2015年12月18日的课程。

因此我的TEMPORARY解决方案。我添加了Furikae字段,因此您可以获得ALL并将结果视为此查询的基线考虑因素。

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状态字段的目的。此外,出勤的确认是专门查找当前日期基础,因为学生可能在一周前参加,但不是基于“今天”参加。

对于索引,我建议如下。同样,不知道班级表是否具有从/到日期考虑

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 )
相关问题