【问题标题】:Can EXISTS make this query more efficient?EXISTS 可以使这个查询更有效吗?
【发布时间】:2011-09-05 13:05:05
【问题描述】:

我只想检索成绩不可接受的学生。我原来的查询是:

SELECT ssm.STUDENT_ID,COUNT(srcg.GRADE_TITLE) AS POSTED_GRADES
    FROM STUDENT_ENROLLMENT ssm, STUDENT_REPORT_CARD_GRADES srcg
    WHERE ssm.SYEAR='2010' 
    AND ssm.SCHOOL_ID='12' 
    AND ssm.GRADE_ID IN ('140','141','142','143','144','145')
    AND srcg.STUDENT_ID=ssm.STUDENT_ID 
    AND srcg.SYEAR='2010' 
    AND srcg.SCHOOL_ID='12' 
    AND srcg.MARKING_PERIOD_ID='434' 
    AND srcg.GRADE_TITLE IN ('1','2','F','D')               
    GROUP BY ssm.STUDENT_ID;

但我不在乎计数;我只想找到成绩不好的学生。我正在尝试另一个查询:

SELECT ssm.STUDENT_ID
    FROM STUDENT_ENROLLMENT ssm
    WHERE ssm.SYEAR='2010' 
    AND ssm.SCHOOL_ID='12' 
    AND ssm.GRADE_ID IN ('140','141','142','143','144','145')
    AND EXISTS(SELECT srcg.GRADE_TITLE from STUDENT_REPORT_CARD_GRADES srcg, STUDENT_ENROLLMENT ssm
    WHERE srcg.STUDENT_ID=ssm.STUDENT_ID 
    AND srcg.SYEAR='2010' 
    AND srcg.SCHOOL_ID='12' 
    AND srcg.MARKING_PERIOD_ID='434' 
    AND srcg.GRADE_TITLE IN ('1','2','F','D'));

但它返回更多记录,所以显然我做错了什么。有没有办法使用 EXISTS 来返回与第一个查询相同的结果,但哪个更有效?

【问题讨论】:

  • 你试过并检查了性能吗?
  • 我看不出有什么错误。是否有可能在 Student_Enrollment 上有重复的 Student_ID?

标签: sql select exists


【解决方案1】:

试试这个

    SELECT distinct ssm.STUDENT_ID
    FROM STUDENT_ENROLLMENT ssm, STUDENT_REPORT_CARD_GRADES srcg
    WHERE ssm.SYEAR='2010' 
    AND ssm.SCHOOL_ID='12' 
    AND ssm.GRADE_ID IN ('140','141','142','143','144','145')    
    AND srcg.STUDENT_ID=ssm.STUDENT_ID 
    AND srcg.SYEAR= ssm.SYEAR 
    AND srcg.SCHOOL_ID=ssm.SCHOOL_ID
    AND srcg.MARKING_PERIOD_ID='434' 
    AND srcg.GRADE_TITLE IN ('1','2','F','D')               

【讨论】:

    【解决方案2】:

    根据我的经验,如果您对效率感兴趣,则不应使用 EXISTS。请尝试以下操作:

    SELECT DISTINCT ssm.STUDENT_ID
    FROM STUDENT_ENROLLMENT ssm
    INNER JOIN STUDENT_REPORT_CARD_GRADES srcg
      ON (srcg.STUDENT_ID = ssm.STUDENT_ID)
    WHERE ssm.SYEAR='2010' AND
          ssm.SCHOOL_ID = '12' AND
          ssm.GRADE_ID IN ('140','141','142','143','144','145') AND
          srcg.SYEAR='2010' AND
          srcg.SCHOOL_ID = '12' AND
          srcg.MARKING_PERIOD_ID = '434' AND
          srcg.GRADE_TITLE IN ('1','2','F','D')
    

    确保您对以下字段或字段组有索引:

    • STUDENT_ENROLLMENT(STUDENT_ID)
    • STUDENT_ENROLLMENT(SYEAR,SCHOOL_ID,GRADE_ID)
    • STUDENT_REPORT_CARD_GRADES(STUDENT_ID)
    • STUDENT_REPORT_CARD_GRADES(SYEAR,SCHOOL_ID,MARKING_PERIOD_ID,GRADE_TITLE)

    此外,请确保您使用的常量与相关列的数据类型相匹配。该语句中的所有常量都以字符串形式给出——所有字段都是真正的字符列,还是数字(例如,STUDENT_ENROLLMENT.SYEAR)?强制数据库执行不必要的转换可能会导致它做一些真正可怕的事情,例如将数字列值转换为字符串,以便可以将转换后的列值与字符串常量进行比较。这可以保证非常慢的表扫描和糟糕的性能。

    分享和享受。

    【讨论】:

      【解决方案3】:

      我长期以来一直不喜欢“distinct”,因为它过去对我隐藏了一些错误。我会推荐这个:

      select STUDENT_ID from 
      (SELECT ssm.STUDENT_ID,COUNT(srcg.GRADE_TITLE) AS POSTED_GRADES
          FROM STUDENT_ENROLLMENT ssm, STUDENT_REPORT_CARD_GRADES srcg
          WHERE ssm.SYEAR='2010' 
          AND ssm.SCHOOL_ID='12' 
          AND ssm.GRADE_ID IN ('140','141','142','143','144','145')
          AND srcg.STUDENT_ID=ssm.STUDENT_ID 
          AND srcg.SYEAR='2010' 
          AND srcg.SCHOOL_ID='12' 
          AND srcg.MARKING_PERIOD_ID='434' 
          AND srcg.GRADE_TITLE IN ('1','2','F','D')               
          GROUP BY ssm.STUDENT_ID);
      

      【讨论】:

      • 同意,我认为DISTINCT 是一种代码异味,因为它通常被用作快速修复以删除重复结果,但会带来可怕的性能后果。
      【解决方案4】:

      您可以在exists 子句中消除与student_enrollment 的连接。

       SELECT ssm.STUDENT_ID, COUNT(*) AS POSTED_GRADES
         FROM STUDENT_ENROLLMENT ssm
        WHERE ssm.SYEAR = '2010' 
          AND ssm.SCHOOL_ID = '12' 
          AND ssm.GRADE_ID IN ('140','141','142','143','144','145')
          AND EXISTS(SELECT srcg.GRADE_TITLE 
                       from STUDENT_REPORT_CARD_GRADES srcg
                      WHERE srcg.SYEAR = '2010' 
                        AND srcg.SCHOOL_ID = '12' 
                        AND srcg.MARKING_PERIOD_ID = '434' 
                        AND srcg.GRADE_TITLE IN ('1','2','F','D')
                    );
      GROUP BY ssm.STUDENT_ID
      

      如果 STUDENT_REPORT_CARD_GRADES 表很大,这可以更快。

      【讨论】:

        【解决方案5】:

        您获得了更多记录,因为您没有像使用GROUP BY 的第一个查询那样消除重复项。将GROUP BY 放回原处,或添加DISTINCT,看看它是如何工作的。

        【讨论】:

          猜你喜欢
          • 2013-02-10
          • 1970-01-01
          • 1970-01-01
          • 2016-04-23
          • 1970-01-01
          • 1970-01-01
          • 2011-07-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多