I have a query I am trying to optimize but the results aren't making sense to me.
It takes roughly 7 seconds to complete this:
SELECT users.*,states.name AS state_name, CONCAT_WS(" - ",L1.updated_at,L1.last_location) AS last_activity,
(SELECT COUNT(*) FROM user_courses WHERE user_id = users.id) AS num_products_total,
(SELECT COUNT(*) FROM user_courses LEFT JOIN courses ON (courses.id = user_courses.course_id) WHERE user_courses.user_id = users.id AND courses.type_id = 5) AS num_products_plt,
(SELECT COUNT(*) FROM user_courses LEFT JOIN courses ON (courses.id = user_courses.course_id) WHERE user_courses.user_id = users.id AND courses.type_id = 7) AS num_products_ce,
(SELECT COUNT(*) FROM user_courses LEFT JOIN courses ON (courses.id = user_courses.course_id) WHERE user_courses.user_id = users.id AND courses.type_id = 6) AS num_products_sh,
(SELECT COUNT(*) FROM user_courses LEFT JOIN courses ON (courses.id = user_courses.course_id) WHERE user_courses.user_id = users.id AND courses.type_id = 8) AS num_products_vc,
(SELECT COUNT(*) FROM user_courses LEFT JOIN courses ON (courses.id = user_courses.course_id) WHERE user_courses.user_id = users.id AND courses.type_id = 9) AS num_products_book
FROM users LEFT JOIN states ON (states.id = users.state_id)
LEFT JOIN logs_user_login AS L1 ON L1.id = (SELECT L2.id FROM logs_user_login AS L2 WHERE L2.user_id = users.id ORDER BY L2.updated_at DESC LIMIT 1) ORDER BY users.id desc LIMIT 0,20;
If I modify (remove counts of course types) to this is takes 2.5 seconds:
SELECT users.*,states.name AS state_name, CONCAT_WS(" - ",L1.updated_at,L1.last_location) AS last_activity
FROM users LEFT JOIN states ON (states.id = users.state_id)
LEFT JOIN logs_user_login AS L1 ON L1.id = (SELECT L2.id FROM logs_user_login AS L2 WHERE L2.user_id = users.id ORDER BY L2.updated_at DESC LIMIT 1) ORDER BY users.id desc LIMIT 0,20;
If I modify (remove get last login log) to this is takes 0.005 seconds:
SELECT users.*,states.name AS state_name,
(SELECT COUNT(*) FROM user_courses WHERE user_id = users.id) AS num_products_total,
(SELECT COUNT(*) FROM user_courses LEFT JOIN courses ON (courses.id = user_courses.course_id) WHERE user_courses.user_id = users.id AND courses.type_id = 5) AS num_products_plt,
(SELECT COUNT(*) FROM user_courses LEFT JOIN courses ON (courses.id = user_courses.course_id) WHERE user_courses.user_id = users.id AND courses.type_id = 7) AS num_products_ce,
(SELECT COUNT(*) FROM user_courses LEFT JOIN courses ON (courses.id = user_courses.course_id) WHERE user_courses.user_id = users.id AND courses.type_id = 6) AS num_products_sh,
(SELECT COUNT(*) FROM user_courses LEFT JOIN courses ON (courses.id = user_courses.course_id) WHERE user_courses.user_id = users.id AND courses.type_id = 8) AS num_products_vc,
(SELECT COUNT(*) FROM user_courses LEFT JOIN courses ON (courses.id = user_courses.course_id) WHERE user_courses.user_id = users.id AND courses.type_id = 9) AS num_products_book
FROM users LEFT JOIN states ON (states.id = users.state_id) ORDER BY users.id desc LIMIT 0,20;
UPDATE I narrowed it down further but still doesn't make sense to my why this is happening. If I remove the L1 table references from the SELECT then the query goes 0.005 again even with the original query that took 7 seconds, the only difference is not grabbing the values from L1.
It takes roughly 0.005 seconds to complete this (Only took the L1 returns out of the select):
SELECT users.*,states.name AS state_name,
(SELECT COUNT(*) FROM user_courses WHERE user_id = users.id) AS num_products_total,
(SELECT COUNT(*) FROM user_courses LEFT JOIN courses ON (courses.id = user_courses.course_id) WHERE user_courses.user_id = users.id AND courses.type_id = 5) AS num_products_plt,
(SELECT COUNT(*) FROM user_courses LEFT JOIN courses ON (courses.id = user_courses.course_id) WHERE user_courses.user_id = users.id AND courses.type_id = 7) AS num_products_ce,
(SELECT COUNT(*) FROM user_courses LEFT JOIN courses ON (courses.id = user_courses.course_id) WHERE user_courses.user_id = users.id AND courses.type_id = 6) AS num_products_sh,
(SELECT COUNT(*) FROM user_courses LEFT JOIN courses ON (courses.id = user_courses.course_id) WHERE user_courses.user_id = users.id AND courses.type_id = 8) AS num_products_vc,
(SELECT COUNT(*) FROM user_courses LEFT JOIN courses ON (courses.id = user_courses.course_id) WHERE user_courses.user_id = users.id AND courses.type_id = 9) AS num_products_book
FROM users LEFT JOIN states ON (states.id = users.state_id)
LEFT JOIN logs_user_login AS L1 ON L1.id = (SELECT L2.id FROM logs_user_login AS L2 WHERE L2.user_id = users.id ORDER BY L2.updated_at DESC LIMIT 1) ORDER BY users.id desc LIMIT 0,20;
Why would I have such a HUGE hit just returning the value from the joined table? It's returning a NULL or a small string under 64 characters.