I think question_engine_data_mapper::load_questions_usages_latest_steps() is the method you are looking for.
https://github.com/moodle/moodle/blob/master/question/engine/datalib.php#L554
I think question_engine_data_mapper::load_questions_usages_latest_steps() is the method you are looking for.
https://github.com/moodle/moodle/blob/master/question/engine/datalib.php#L554
Thanks again Tim for your fantastic suggestion.
It reduced the process of determining a quiz's completion from 500ms to 60ms for a 134 question quiz.
Unfortunately, this 60ms is still too much (given these progress bars are on a landing page with a list of up to 30 quizzes), so I've had to go against best practices and directly execute a slightly modified version of the query triggered by:
question_engine_data_mapper::load_questions_usages_latest_steps()
As follows:
$sql = "SELECT COUNT(*)This query takes approx 13-25ms to execute.
FROM {question_attempts} qa
JOIN {question_attempt_steps} qas
ON qas.questionattemptid = qa.id
AND qas.sequencenumber = (SELECT MAX(sequencenumber) FROM {question_attempt_steps} WHERE questionattemptid = qa.id)
WHERE qa.questionusageid = ?
AND state = ?";
$num_answered = $DB->count_records_sql($sql, array($question_usage_id, 'complete'));
Thanks again
In fact hard coding
AND qas.sequencenumber = (SELECT MAX(sequencenumber) FROM {question_attempt_steps} WHERE questionattemptid = qa.id)
to AND qas.sequencenumber = 1reduces the time to 1ms
Well, replacing the whole query with
SELECT 1
would be even faster still. There is no point speeding up the query by changing it to give the wrong answer.
Your fundamental problem is doing one DB query for each quiz attempt. You should be trying to load all the data for all attempts in one query, and you can, using the method I suggested, if you understand the qubaid_condition part of the API.