请检查我的MYSQL查询&给我建议?

时间:2010-06-16 03:09:07

标签: mysql

这是我的mysql查询。

SELECT s.s_nric                           AS nric,
       s.s_name                           AS name,
       s.s_psle_eng                       AS psle_eng,
       s.s_psle_math                      AS psle_maths,
       s.s_psle_aggr                      AS psle_aggr,
       (SELECT re.re_mark
        FROM   si_results re
        WHERE  re.re_code LIKE 'FEEN%'
               AND re.re_year = '2008'
               AND re.re_semester = '2'
               AND re.re_nric = s.s_nric) AS english_2008,
       (SELECT re.re_mark
        FROM   si_results re
        WHERE  re.re_code LIKE 'FEMA%'
               AND re.re_year = '2008'
               AND re.re_semester = '2'
               AND re.re_nric = s.s_nric) maths_2008,
       (SELECT re.re_mark
        FROM   si_results re
        WHERE  re.re_code LIKE 'FEEN%'
               AND re.re_year = '2009'
               AND re.re_semester = '2'
               AND re.re_nric = s.s_nric) AS english_2009,
       (SELECT re.re_mark
        FROM   si_results re
        WHERE  re.re_code LIKE 'FEMA%'
               AND re.re_year = '2009'
               AND re.re_semester = '2'
               AND re.re_nric = s.s_nric) maths_2009,
       isc.isc_g_gpa                      AS isc_gpa
FROM   si_student_data AS s
       LEFT JOIN si_isc_gpa AS isc
         ON isc.isc_g_nric = s.s_nric
WHERE  1 = 1
       AND s.s_admission_year = '2008'
GROUP  BY s.s_nric
ORDER  BY s.s_gender,
          s.s_name ASC 

请检查我的子查询

这是我的子查询

(SELECT re.re_mark 
  FROM si_results re 
  WHERE re.re_code like 'FEEN%' 
    AND re.re_year='2008' 
    AND re.re_semester='2' 
    AND re.re_nric=s.s_nric) as English_2008, 
(SELECT re.re_mark 
  FROM si_results re 
  WHERE re.re_code like 'FEMA%' 
    AND re.re_year='2008' 
    AND re.re_semester='2' 
    AND re.re_nric=s.s_nric) Maths_2008, 
(SELECT re.re_mark 
  FROM si_results re 
  WHERE re.re_code like 'FEEN%' 
    AND re.re_year='2009' 
    AND re.re_semester='2' 
    AND re.re_nric=s.s_nric ) as English_2009, 
(SELECT re.re_mark 
  FROM si_results re 
  WHERE re.re_code like 'FEMA%' 
    AND re.re_year='2009' 
    AND re.re_semester='2' 
    AND re.re_nric=s.s_nric ) Maths_2009

当我执行查询时,服务器需要很长时间才能执行。那怎么简单呢? 请告诉我。

感谢。

3 个答案:

答案 0 :(得分:5)

重要的是要知道,如果没有编入索引,那么LIKE 'XXXX%'非常慢。在某些情况下,这可能需要永远。此外,你正在做四个子选择而不是连接,这又慢了。下面我添加了一个完整的查询,它将产生相同的结果。替代方法是通过减少连接数来减小查询的大小,而是使用NORMALIZED输出。对于每个nricname,对于每种类型的课程(英语,数学,2008年,2009年等),您将拥有多行,而不是re_mark包含代码(FEEN或FEMA)和标记的列。

尝试以下查询,看看它是否适合您:

SELECT s.s_nric                           AS nric,
       s.s_name                           AS name,
       s.s_psle_eng                       AS psle_eng,
       s.s_psle_math                      AS psle_maths,
       s.s_psle_aggr                      AS psle_aggr,
       e_2008_feen.re_mark                AS english_2008,
       e_2008_fema.re_mark                AS maths_2008,
       e_2009_feen.re_mark                AS english_2009,
       e_2009_fema.re_mark                AS maths_2009,
       isc.isc_g_gpa                      AS isc_gpa
FROM   si_student_data AS s
INNER JOIN si_results e_2008_feen
    ON e_2008_feen.re_code LIKE 'FEEN%'
       AND e_2008_feen.re_year = '2008'
       AND e_2008_feen.re_semester = '2'
       AND e_2008_feen.re_nric = s.s_nric

INNER JOIN si_results e_2008_fema
    ON e_2008_fema.re_code LIKE 'FEMA%'
       AND e_2008_fema.re_year = '2008'
       AND e_2008_fema.re_semester = '2'
       AND e_2008_fema.re_nric = s.s_nric

INNER JOIN si_results e_2009_feen
    ON e_2009_feen.re_code LIKE 'FEEN%'
       AND e_2009_feen.re_year = '2009'
       AND e_2009_feen.re_semester = '2'
       AND e_2009_feen.re_nric = s.s_nric

INNER JOIN si_results e_2009_fema
    ON e_2009_fema.re_code LIKE 'FEMA%'
       AND e_2009_fema.re_year = '2009'
       AND e_2009_fema.re_semester = '2'
       AND e_2009_fema.re_nric = s.s_nric

LEFT JOIN si_isc_gpa AS isc
    ON isc.isc_g_nric = s.s_nric

WHERE  s.s_admission_year = '2008'
GROUP  BY s.s_nric
ORDER  BY s.s_gender,
          s.s_name ASC

编辑:包含标准化版本:

SELECT s.s_nric                           AS nric,
       s.s_name                           AS name,
       s.s_psle_eng                       AS psle_eng,
       s.s_psle_math                      AS psle_maths,
       s.s_psle_aggr                      AS psle_aggr,
       si_results.re_code                 AS code
       si_results.re_mark                 AS mark
       si_results.re_year                 AS year
       isc.isc_g_gpa                      AS isc_gpa

FROM   si_student_data AS s

INNER JOIN si_results e_2008_feen
    ON si_results.re_nric = s.s_nric

LEFT JOIN si_isc_gpa AS isc
    ON isc.isc_g_nric = s.s_nric

WHERE  s.s_admission_year = '2008'
    AND si_results.re_year in ('2008', '2009')
    AND si_results.re_semester = '2'
    AND (
          si_results.re_code LIKE 'FEEN%'
          OR si_results.re_code LIKE 'FEMA%'
     )

GROUP  BY s.s_nric
ORDER  BY s.s_gender,
          s.s_name ASC

这将产生如下行:

nric: 1
name: 'student 1'
psle_eng: eng1
psle_maths: maths1
psle_aggr: aggr1
code: FEENXXXX
mark: 5
year: 2008
isc_gpa: gpa1



nric: 1
name: 'student 1'
psle_eng: eng1
psle_maths: maths1
psle_aggr: aggr1
code: FEENXXXX
mark: 3
year: 2009
isc_gpa: gpa1


nric: 1
name: 'student 1'
psle_eng: eng1
psle_maths: maths1
psle_aggr: aggr1
code: FEMAXXXX
mark: 4.5
year: 2008
isc_gpa: gpa1


nric: 1
name: 'student 1'
psle_eng: eng1
psle_maths: maths1
psle_aggr: aggr1
code: FEMAXXXX
mark: 5
year: 2009
isc_gpa: gpa1

请注意,四个记录的唯一值更改为codemarkyear。你将获得4倍的记录数量,但它的运行速度也应该比之前快得多。您的代码必须迭代所有行并根据需要聚合它们。

答案 1 :(得分:2)

尝试这样的事情:

  re1.re_mark AS english_2008,
  re2.re_mark AS maths_2008,
  re3.re_mark AS english_2009,
  re4.re_mark AS maths_2009,
  isc.isc_g_gpa AS isc_gpa

FROM   si_student_data AS s
  INNER JOIN si_results as re1 ON re1.re_code LIKE 'FEEN%' AND re1.re_year = '2008' 
            AND re1.re_semester = '2' AND re1.re_nric = s.s_nric
  INNER JOIN si_results as re2 ON re2.re_code LIKE 'FEMA%' AND re2.re_year = '2008' 
            AND re2.re_semester = '2' AND re2.re_nric = s.s_nric
  INNER JOIN si_results as re3 ON re3.re_code LIKE 'FEEN%' AND re3.re_year = '2009' 
            AND re3.re_semester = '2' AND re3.re_nric = s.s_nric
  INNER JOIN si_results as re4 ON re4.re_code LIKE 'FEMA%' AND re4.re_year = '2009' 
            AND re4.re_semester = '2' AND re4.re_nric = s.s_nric    

如果需要,用LEFT JOIN替换INNER JOIN

如果这个解决方案还不够,还有两个选择:

  • 使用视图(每个条件为1)

    创建视图FEEN2008 AS   SELECT re_mark,re_nric   来自si_results作为re   在哪里re.re_code喜欢'FEEN%'         AND re.re_year ='2008'         AND re.re_semester ='2'

    并用以下内容替换原始查询:

     FROM   si_student_data AS s
        INNER JOIN FEEN2008 as re1 ON re1.re_nric = s.s_nric
        INNER JOIN FEMA2008 as re2 ON re2.re_nric = s.s_nric
        INNER JOIN FEEN2009 as re3 ON re3.re_nric = s.s_nric      
        INNER JOIN FEMA2009 as re4 ON re4.re_nric = s.s_nric
    

    数据库引擎通常会优化视图,而且速度可能更快。不知道MySql如何与他们合作。

  • 使用字段在si_results中创建索引:re_code,re_year,re_semester和re_nric 请注意,这会使插入和更新变慢。

答案 2 :(得分:0)

这样的子查询对我来说总是很可疑。检查其他获取数据的方法非常诱人......或许还要加入到桌面上? si_results表使用了3次,并且向我提出了一个红旗,作为重写为左连接的好选择。虽然如此,只有3000行,它确实不应该导致太慢。

相反,删除子查询并再次检查性能。也许你真正需要的只是一个新的索引。