For the query above, the following recommendations will be helpful as part of the SQL tuning process.
You'll find 3 sections below:
The optimization process and recommendations:
- Avoid Calling Functions With Indexed Columns (query line: 35): When a function is used directly on an indexed column, the database's optimizer won’t be able to use the index. For example, if the column `EmployeeID` is indexed, the index won’t be used as it’s wrapped with the function `LEN`. If you can’t find an alternative condition that won’t use a function call, a possible solution is to store the required value in a new indexed column.
- Create Optimal Indexes (modified query below): The recommended indexes are an integral part of this optimization effort and should be created before testing the execution duration of the optimized query.
- Explicitly ORDER BY After GROUP BY (modified query below): By default, the database sorts all 'GROUP BY col1, col2, ...' queries as if you specified 'ORDER BY col1, col2, ...' in the query as well. If a query includes a GROUP BY clause but you want to avoid the overhead of sorting the result, you can suppress sorting by specifying 'ORDER BY NULL'.
- Remove Redundant Left Joins (modified query below): Redundant LEFT JOINs (e.g. `SiteMaster`) were detected in the query. Removing them will result in a performance improvement. In some cases, JOINs become redundant after an optimization is applied, such as when converting OR conditions to a UNION clause.
- Remove Redundant Left Joins (modified query below): Redundant LEFT JOINs (e.g. `Accounts`) were detected in the query. Removing them will result in a performance improvement. In some cases, JOINs become redundant after an optimization is applied, such as when converting OR conditions to a UNION clause.
- Remove Redundant Left Joins (modified query below): Redundant LEFT JOINs (e.g. `DriveMaster`) were detected in the query. Removing them will result in a performance improvement. In some cases, JOINs become redundant after an optimization is applied, such as when converting OR conditions to a UNION clause.
Optimal indexes for this query:
ALTER TABLE `People` ADD INDEX `people_idx_personid` (`PersonID`);
ALTER TABLE `PeopleStaffingDetail` ADD INDEX `peoplestaffingdeta_idx_personid` (`PersonID`);
ALTER TABLE `PeopleStaffingRoleDetail` ADD INDEX `peoplestaffingrole_idx_personid_roleid` (`PersonID`,`RoleID`);
ALTER TABLE `StaffingEventMaster` ADD INDEX `staffingeventmaste_idx_eventid` (`EventID`);
ALTER TABLE `StaffingEventShiftDetail` ADD INDEX `staffingeventshift_idx_shiftid` (`ShiftID`);
The optimized query:
SELECT
PEVD.EmployeeID[EmployeeID],
P.PersonID,
SEM.eventbegindate[EventDate],
LEFT(CONVERT(varchar(20),
MIN(PSD.StartTime),
108),
5)[StartTime],
LEFT(CONVERT(varchar(20),
MAX(PSD.EndTime),
108),
5)[EndTime],
CASE
WHEN DAY(MIN(PSD.StartTime)) <> DAY(MAX(PSD.EndTime)) THEN 1
ELSE 0 END[IsAddDay] FROM
StaffingEventMaster SEM
INNER JOIN
StaffingEventShiftDetail SESD
ON SEM.EventID = SESD.EventID
INNER JOIN
PeopleStaffingDetail PSD
ON SESD.ShiftID = PSD.ShiftID
INNER JOIN
People P
ON PSD.PersonID = P.PersonID
INNER JOIN
PeopleEmployeeValueDetail PEVD
ON PEVD.PersonID = P.PersonID
INNER JOIN
PeopleStaffingRoleDetail PSRD
ON P.PersonID = PSRD.PersonID
AND PSRD.RoleID <> 153
WHERE
LEN(PEVD.EmployeeID) > 0
GROUP BY
PEVD.EmployeeID,
P.PersonID,
SEM.EventBeginDate
ORDER BY
NULL