Reputation: 111
Ok, I used MySQL/postgres for many years before moving to MongoDB for the past 6yrs and I'm drawing some blanks now. I've been looking around on the best way to do this and with my very simple dataset the querytime is an average of 20ms. Seems crazy for < 100 rows. I probably did this the super complex way :)
So the idea here is to get a list of the lessons the user has access to, along with their LATEST quiz score and LATEST lesson progress (how far they made it in the lesson).
SELECT DISTINCT ON (m.id) m.id,m.lesson_name,m.course_name,m.order,m.progress,m.thumb,m.media_id,m.length,m.quiz_id,m.score FROM (SELECT
lessons.id,lessons.name AS lesson_name,courses.name AS course_name, lesson_courses."order", less_prog.progress, lessons.thumb, lessons.media_id, lessons.length, lesson_quiz.id as quiz_id, acclessq.score,acclessq.timestamp as atime, less_prog.timestamp as ltime
FROM lessons
INNER JOIN lesson_courses ON lessons."id" = lesson_courses.lessons_id
INNER JOIN plan_courses ON plan_courses.courses_id = lesson_courses.courses_id
INNER JOIN courses ON courses.id = lesson_courses.courses_id
LEFT JOIN (
SELECT progress,lessons_id,timestamp FROM lesson_progress WHERE accounts_id = 1
) as less_prog ON less_prog.lessons_id = lessons.id
LEFT JOIN (
SELECT lesson_quiz.id,lesson_quiz.lessons_id FROM lesson_quiz
) as lesson_quiz ON lessons.id=lesson_quiz.lessons_id
LEFT JOIN (
SELECT score,lesson_quiz_id,account_lesson_quiz.timestamp FROM account_lesson_quiz WHERE account_lesson_quiz.accounts_id = 1
) as acclessq ON lesson_quiz.id=acclessq.lesson_quiz_id
LEFT JOIN (
SELECT accounts_id,plans_id FROM account_plans WHERE accounts_id = 1
) as account_plans ON account_plans.plans_id = plan_courses.plans_id
GROUP BY lessons.id,courses.id,courses.name,lesson_courses.order,less_prog.progress, lessons.thumb, lessons.media_id, lessons.length, quiz_id, acclessq.score,atime,ltime
ORDER BY courses.id, lesson_courses."order",atime DESC,ltime DESC) m
I'm sure I've done it way too crazy, but I get the right results... So how can I simplify it and get the performance down for when we have more results?
UPDATE: Tried rewriting using WITH's. Dropped perf to an average of 15ms. It does look much cleaner but I still feel it's way too high for this little amount of data.
WITH lesson_quiz AS (SELECT lesson_quiz.id,lesson_quiz.lessons_id FROM
lesson_quiz),
less_prog AS (SELECT progress,lessons_id,timestamp FROM lesson_progress
WHERE accounts_id = 1),
acclessq AS (SELECT score,lesson_quiz_id,account_lesson_quiz.timestamp
FROM account_lesson_quiz WHERE account_lesson_quiz.accounts_id = 1),
acc_plans AS (SELECT accounts_id,plans_id FROM account_plans WHERE
accounts_id = 1)
SELECT DISTINCT ON (lessons.id)
lessons.id,lessons.name AS lesson_name,courses.name AS course_name, lesson_courses."order", less_prog.progress, lessons.thumb, lessons.media_id, lessons.length, lesson_quiz.id as quiz_id, acclessq.score
FROM lessons
INNER JOIN lesson_courses ON lessons."id" = lesson_courses.lessons_id
INNER JOIN plan_courses ON plan_courses.courses_id = lesson_courses.courses_id
INNER JOIN courses ON courses.id = lesson_courses.courses_id
LEFT JOIN less_prog ON less_prog.lessons_id = lessons.id
LEFT JOIN lesson_quiz ON lessons.id=lesson_quiz.lessons_id
LEFT JOIN acclessq ON lesson_quiz.id=acclessq.lesson_quiz_id
LEFT JOIN acc_plans ON acc_plans.plans_id = plan_courses.plans_id
ORDER BY id, acclessq.timestamp DESC, less_prog.timestamp DESC
Here is the query plan: https://explain.depesz.com/s/IvPl
Upvotes: 0
Views: 76
Reputation: 111
It ended up coming down to the computer. I was testing on my latest edition, fully maxed Macbook Pro. Switching to my desktop, I'm not consistently getting >0.9ms.
Upvotes: 0
Reputation: 1355
GROUP BY and DISTINCT are often achieving the same thing. Are you sure you need DISTINCT and if so does it perform better when you remove it?
Thanks for the query plan. Maybe an index on the timestamp DESC columns will help? Seems like the majority of the time is spent sorting.
Upvotes: 2
Reputation: 939
WITH Queries may look like more elegant. Another option is to create a View.
Upvotes: 1