首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UNION ALL的慢查询

问UNION ALL的慢查询
EN

Stack Overflow用户
提问于 2015-12-18 20:55:47
回答 2查看 72关注 0票数 0

我得到了一个查询,它给出了我想要的结果,但执行起来却耗费了很长时间。有人能给我一些建议来加速这个查询吗?

下面是查询:

代码语言:javascript
复制
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

基本上我的数据库结构是这样的:

代码语言:javascript
复制
StudentDB
ClassDB
RegDB
AttendanceDB

StudentDB (这个有很多列,其中包含学生的电话号码等数据,这些数据是无关的,我将删除这些列以进行缩写)

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
regid   int(11)         No  None    AUTO_INCREMENT  
classid int(11)         No  None    
studentid   int(11)         No  None    

AttendanceDB

代码语言:javascript
复制
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记录哪些学生实际参加了哪个课程,以及记录哪些学生将加入(将来)不是他们的常规课程的课程。

我想对这个选择做的是获得所有注册到某个班级或有不定期预约的学生,减去已经标记为当天签到的学生。

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

EN

回答 2

Stack Overflow用户

发布于 2015-12-18 21:24:17

让我们将联合的第一部分称为query1,将联合的第二部分称为query2。现在在query1 AttendenceDB中是中间表b/n studentDB和ClassDB,在query2 RegDB中是中间表b/n studentDB和ClassDB。其他条件也是一样的。如果我们先将RegDB和AttendenceDB的条件合并,然后将合并的结果与studentDB和ClassDB连接起来,就可以避免不必要的连接。

票数 1
EN

Stack Overflow用户

发布于 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字段,这样您就可以获得所有内容,并将结果作为此查询的基线考虑因素。

代码语言:javascript
复制
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考虑

代码语言:javascript
复制
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 )
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34356206

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档