Reputation: 103
I have a SQL Query that's taking over 3.5 seconds to return a count. Looking at the trace of the query it looks like all the indexes are being used. What can I do to optimize this to reasonable execution?
My thanks in advance.
SQL details
Query
SELECT count(DISTINCT `workorders`.id) AS count_all FROM `workorders`
LEFT OUTER JOIN `users` ON `users`.id = `workorders`.user_id
LEFT OUTER JOIN `assets` ON `assets`.id = `workorders`.asset_id
LEFT OUTER JOIN `users` completed_by_users_workorders ON `completed_by_users_workorders`.id = `workorders`.completed_by_user_id
LEFT OUTER JOIN `messages` ON messages.workorder_id = workorders.id LEFT OUTER JOIN `priorities` ON `priorities`.id = `workorders`.priority_id
LEFT OUTER JOIN `suspension_reasons` ON `suspension_reasons`.id = `workorders`.suspension_reason_id
LEFT OUTER JOIN `job_types` ON `job_types`.id = `workorders`.job_type_id
LEFT OUTER JOIN `workorder_statuses` ON `workorder_statuses`.id = `workorders`.workorder_status_id
LEFT OUTER JOIN `workorder_types` ON `workorder_types`.id = `workorders`.workorder_type_id
LEFT OUTER JOIN `workorder_tasks` ON workorder_tasks.workorder_id = workorders.id
LEFT OUTER JOIN `frequencies` ON `frequencies`.id = `workorder_tasks`.frequency_id
LEFT OUTER JOIN `facilities` ON `facilities`.id = `workorders`.facility_id
LEFT OUTER JOIN `locations` ON `locations`.id = `workorders`.location_id
WHERE ((((workorders.workorder_status_id = ?)) AND (workorders.application = ?)) AND (workorders.facility_id = ?))
Duration 3,791 ms Query analysis (show details)
Trace
*workorders*
The table was retrieved with this index: facility_id,app_fac,workorder_status_id
You can speed up this query by querying only fields that are within the index. Or you can create an index that includes every field in your query, including the primary key.
Approximately 33850 rows of this table were scanned.
users
The table was retrieved with this index: PRIMARY
Approximately 1 row of this table was scanned.
assets
The table was retrieved with this index: PRIMARY
Approximately 1 row of this table was scanned.
completed_by_users_workorders
The table was retrieved with this index: PRIMARY
Approximately 1 row of this table was scanned.
messages
The table was retrieved with this index: workorder_id
Approximately 2 rows of this table were scanned.
priorities
The table was retrieved with this index: PRIMARY
Approximately 1 row of this table was scanned.
suspension_reasons
The table was retrieved with this index: PRIMARY
Approximately 1 row of this table was scanned.
job_types
The table was retrieved with this index: PRIMARY
Approximately 1 row of this table was scanned.
workorder_statuses
The table was retrieved with this index: PRIMARY
Approximately 1 row of this table was scanned.
workorder_types The table was retrieved with this index: PRIMARY
Approximately 1 row of this table was scanned.
workorder_tasks The table was retrieved with this index: index_workorder_tasks_on_workorder_id You can speed up this query by querying only fields that are within the index. Or you can create an index that includes every field in your query, including the primary key.
Approximately 1 row of this table was scanned.
frequencies The table was retrieved with this index: PRIMARY
Approximately 1 row of this table was scanned.
facilities
The table was retrieved with this index: PRIMARY
Approximately 1 row of this table was scanned.
locations
The table was retrieved with this index: PRIMARY
Approximately 1 row of this table was scanned.
Upvotes: 0
Views: 249
Reputation: 37354
Unless I'm missing something, you have bunch of LEFT JOIN
s which don't affect final results ( you are selecting distinct workorders.id
- I guess it's a PK column. Then only where is important , WHERE ((((workorders.workorder_status_id = ?)) AND (workorders.application = ?)) AND (workorders.facility_id = ?)
. So I believe you can get rid of all LEFT JOIN
s and write just select from 1 table making life of optimizer much easier ....
SELECT count(*) AS count_all
FROM `workorders`
WHERE ((((workorders.workorder_status_id = ?)) AND (workorders.application = ?)) AND
(workorders.facility_id = ?)
The query above should give you the same result as your original query but with much less efforts.
Upvotes: 2