2015-10-29 5 views
0

У меня есть отчет, который нужно выполнить, чтобы удовлетворить наши требования к отчетности для правительственного органа. Ожидается, что отчет будет возвращать нагрузку для каждого учащегося в каждом модуле на определенный период времени.Запрос MYSQL берет навсегда

Например, отчет должен вернуть учащихся, обучающихся в данном модуле, для данного приема в данном году и семестре с датой переписи (указанная правительством дата, после которой ученик несет ответственность за стоимость блок, даже если они снять)

Так я написал этот MySQL Query

SELECT 
    e.enrolstudent AS '313', 
    (SELECT c.ntiscode FROM course c WHERE c.courseid=ec.courseid) AS '307', 
    e.startdate as '534', 
    'AOU' as '333', 
    m.mod_eftsl as '339', 
    e.enrolmod as '354', 
    e.census_date as '489', 
    m.diciplinecode as '464', 
    (CASE 
     WHEN m.mode = 'Face to Face' THEN 1 
     WHEN m.mode = 'Online' THEN 2 
     WHEN m.mode = 'RPL' THEN 5 
     ELSE 3  
    END) AS '329', 
    'A6090' as '477', 
    up.citizen AS '358', 
    vf.maxcontribute as '392', 
    vf.studentstatus as '490', 
    vf.total_amount_charged as '384', 
    vf.amount_paid as '381', 
    vf.loan_fee as '529', 
    u.chessn as '488', 
    m.workexp as '337', 
    '0' as '390', 
    m.sumwinschool as '551', 
    vf.help_debt as '558' 
FROM 
    enrolment e 
    INNER JOIN enrolcourse AS ec ON ec.studentid=e.enrolstudent 
    INNER JOIN vetfee AS vf ON vf.userid=e.enrolstudent 
    INNER JOIN users AS u ON u.userid = e.enrolstudent 
    INNER JOIN users_personal AS up ON up.userid = e.enrolstudent 
    INNER JOIN module AS m ON m.modshortname = e.enrolmod 
WHERE 
     e.online_intake in (select oi.intakecode from online_intake oi where STR_TO_DATE(oi.censusdate,'%d-%m-%Y') > '2015-07-01' and STR_TO_DATE(oi.censusdate,'%d-%m-%Y') < '2015-09-31') AND 
     e.enrolstudent NOT LIKE '%onlinetutor%' AND 
     e.enrolstudent NOT LIKE '%tes%' AND 
     e.enrolstudent NOT like '%student%' AND 
     e.enrolrole = 'student' 
ORDER BY e.enrolstudent;" 

Это, кажется, висит, я оставил его работать в течение часа без результата. В таблице регистрации всего 10189 записей, 1538 в регистрации, 650 в модуле. Я не думаю, что его количество записей, я предполагаю, что я только что построил свой запрос неправильно, впервые используя объединения (кроме естественного). Любые идеи или советы по улучшению этого будут очень признательны.

select count(*) from enrolment; 
+----------+ 
| count(*) | 
+----------+ 
| 10189 | 
+----------+ 

select count(*) from enrolcourse; 
+----------+ 
| count(*) | 
+----------+ 
|  1538 | 
+----------+ 

select count(*) from vetfee; 
+----------+ 
| count(*) | 
+----------+ 
|  1538 | 
+----------+ 

select count(*) from users; 
+----------+ 
| count(*) | 
+----------+ 
|  1249 | 
+----------+ 

select count(*) from users_personal; 
+----------+ 
| count(*) | 
+----------+ 
|  941 | 
+----------+ 

select count(*) from module; 
+----------+ 
| count(*) | 
+----------+ 
|  650 | 

Вот результаты Объяснения

+----+--------------------+-------+------+---------------+------+---------+------+-------+---------------------------------+ 
| id | select_type  | table | type | possible_keys | key | key_len | ref | rows | Extra       | 
+----+--------------------+-------+------+---------------+------+---------+------+-------+---------------------------------+ 
| 1 | PRIMARY   | m  | ALL | NULL   | NULL | NULL | NULL | 691 | Using temporary; Using filesort | 
| 1 | PRIMARY   | up | ALL | NULL   | NULL | NULL | NULL | 987 | Using join buffer    | 
| 1 | PRIMARY   | u  | ALL | NULL   | NULL | NULL | NULL | 1180 | Using where; Using join buffer | 
| 1 | PRIMARY   | ec | ALL | NULL   | NULL | NULL | NULL | 1607 | Using where; Using join buffer | 
| 1 | PRIMARY   | e  | ALL | NULL   | NULL | NULL | NULL | 10629 | Using where; Using join buffer | 
| 1 | PRIMARY   | vf | ALL | NULL   | NULL | NULL | NULL | 10959 | Using where; Using join buffer | 
| 3 | DEPENDENT SUBQUERY | oi | ALL | NULL   | NULL | NULL | NULL | 42 | Using where      | 
| 2 | DEPENDENT SUBQUERY | c  | ALL | NULL   | NULL | NULL | NULL | 23 | Using where      | 
+----+--------------------+-------+------+---------------+------+---------+------+-------+---------------------------------+ 
+0

Сколько записей у каждого из таблиц есть? –

+1

Добавьте индексы во все столбцы, используемые для объединений. –

+1

Что показывает ['EXPLAIN'] (https://dev.mysql.com/doc/refman/5.0/en/explain.html)? –

ответ

1

Избавиться от этих коррелированных подзапросов. Вместо этого используйте соединение.

Кроме того, использование BETWEEN уменьшить себя один STR_TO_DATE позвонить

Наконец, вы должны смотреть на способ устранения всех этих LIKE вызовов.

SELECT 
    e.enrolstudent AS '313', 
    c.ntiscode AS '307', 
    e.startdate as '534', 
    'AOU' as '333', 
    m.mod_eftsl as '339', 
    e.enrolmod as '354', 
    e.census_date as '489', 
    m.diciplinecode as '464', 
    (CASE 
     WHEN m.mode = 'Face to Face' THEN 1 
     WHEN m.mode = 'Online' THEN 2 
     WHEN m.mode = 'RPL' THEN 5 
     ELSE 3  
    END) AS '329', 
    'A6090' as '477', 
    up.citizen AS '358', 
    vf.maxcontribute as '392', 
    vf.studentstatus as '490', 
    vf.total_amount_charged as '384', 
    vf.amount_paid as '381', 
    vf.loan_fee as '529', 
    u.chessn as '488', 
    m.workexp as '337', 
    '0' as '390', 
    m.sumwinschool as '551', 
    vf.help_debt as '558' 
FROM 
    enrolment e 
    INNER JOIN enrolcourse AS ec ON ec.studentid=e.enrolstudent 
    INNER JOIN course AS c ON c.courseid = ec.courseid 
    INNER JOIN vetfee AS vf ON vf.userid=e.enrolstudent 
    INNER JOIN users AS u ON u.userid = e.enrolstudent 
    INNER JOIN users_personal AS up ON up.userid = e.enrolstudent 
    INNER JOIN module AS m ON m.modshortname = e.enrolmod 
    INNER JOIN online_intake oi ON oi.intakecode = e.online_intake 
     AND STR_TO_DATE(oi.censusdate, '%d-%m-%Y') BETWEEN '2015-07-01' AND '2015-09-31' 
WHERE e.enrolstudent NOT LIKE '%onlinetutor%' 
    AND e.enrolstudent NOT LIKE '%tes%' 
    AND e.enrolstudent NOT like '%student%' 
    AND e.enrolrole = 'student' 
ORDER BY e.enrolstudent; 

Учитывая ваш размещенную EXPLAIN выхода, вы также хотите, чтобы добавить следующие показатели:

ALTER TABLE enrolment 
    ADD INDEX (enrolstudent), 
    ADD INDEX (enrolmod), 
    ADD INDEX (online_intake); 
ALTER TABLE enrolcourse 
    ADD INDEX (studentid), 
    ADD INDEX (courseid); 
ALTER TABLE course 
    ADD INDEX (courseid); 
ALTER TABLE vetfee 
    ADD INDEX (userid); 
ALTER TABLE users 
    ADD INDEX (userid); 
ALTER TABLE users_personal 
    ADD INDEX (userid); 
ALTER TABLE module 
    ADD INDEX (modshortname); 
ALTER TABLE online_intake 
    ADD INDEX (intakecode); 
+0

Привет, Стив, я изначально тоже присоединился к этому. Я поменял его и все еще не закончил. –

+0

Да, просто создавая их сейчас. Я посмотрю, как это происходит. –

+0

@PeterKelly - я сделал несколько дополнительных настроек для запроса (исключил другой коррелированный подзапрос и исключил вызов STR_TO_DATE). Это должно ускорить его еще немного. –

Смежные вопросы