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: 58): 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 `jobtitle` is indexed, the index won’t be used as it’s wrapped with the function `LOWER`. 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.
- Avoid Calling Functions With Indexed Columns (query line: 59): 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 `jobmaincategory` is indexed, the index won’t be used as it’s wrapped with the function `LOWER`. 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.
- Avoid Calling Functions With Indexed Columns (query line: 60): 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 `jobsubcategory` is indexed, the index won’t be used as it’s wrapped with the function `LOWER`. 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.
- Avoid Calling Functions With Indexed Columns (query line: 61): 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 `jobdescription` is indexed, the index won’t be used as it’s wrapped with the function `LOWER`. 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.
- Avoid Calling Functions With Indexed Columns (query line: 62): 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 `jobcountry` is indexed, the index won’t be used as it’s wrapped with the function `LOWER`. 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.
- Avoid LIKE Searches With Leading Wildcard (query line: 58): The database will not use an index when using like searches with a leading wildcard (e.g. '%taxi%'). Although it's not always a satisfactory solution, please consider using prefix-match LIKE patterns (e.g. 'TERM%').
- Avoid LIKE Searches With Leading Wildcard (query line: 59): The database will not use an index when using like searches with a leading wildcard (e.g. '%taxi%'). Although it's not always a satisfactory solution, please consider using prefix-match LIKE patterns (e.g. 'TERM%').
- Avoid LIKE Searches With Leading Wildcard (query line: 60): The database will not use an index when using like searches with a leading wildcard (e.g. '%taxi%'). Although it's not always a satisfactory solution, please consider using prefix-match LIKE patterns (e.g. 'TERM%').
- Avoid LIKE Searches With Leading Wildcard (query line: 61): The database will not use an index when using like searches with a leading wildcard (e.g. '%taxi%'). Although it's not always a satisfactory solution, please consider using prefix-match LIKE patterns (e.g. 'TERM%').
- Avoid LIKE Searches With Leading Wildcard (query line: 62): The database will not use an index when using like searches with a leading wildcard (e.g. '%taxi%'). Although it's not always a satisfactory solution, please consider using prefix-match LIKE patterns (e.g. 'TERM%').
- Avoid OR Conditions By Using UNION (modified query below): In mosts cases, filtering using the OR operator cannot be applied using indexes. A more optimized alternative will be to split the query to two parts combined with a UNION clause, while each query holds one part of the original OR condition.
- 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.
- Use UNION ALL instead of UNION (query line: 48): Always use UNION ALL unless you need to eliminate duplicate records. By using UNION ALL, you'll avoid the expensive distinct operation the database applies when using a UNION clause.
Optimal indexes for this query:
ALTER TABLE `job` ADD INDEX `job_idx_jobbusi_jobfixe_jobfixe_jobendd` (`jobbusiness`,`jobfixedstartdate`,`jobfixedenddate`,`jobenddate`);
ALTER TABLE `job` ADD INDEX `job_idx_jobbusi_jobfixe_jobfixe_jobstar` (`jobbusiness`,`jobfixedstartdate`,`jobfixedenddate`,`jobstartdate`);
ALTER TABLE `job` ADD INDEX `job_idx_jobbusi_jobfixe_jobfixe_jobdate` (`jobbusiness`,`jobfixedstartdate`,`jobfixedenddate`,`jobdateadded`);
ALTER TABLE `job` ADD INDEX `job_idx_jobdele_jobpaye_jobbusi_jobstar` (`jobdeleted`,`jobpayed`,`jobbusiness`,`jobstartdate`);
The optimized query:
SELECT
job_jobunique,
job_jobtypeunique,
job_joblat,
job_joblng
FROM
((SELECT
job.jobunique AS job_jobunique,
job.jobtypeunique AS job_jobtypeunique,
job.joblat AS job_joblat,
job.joblng AS job_joblng
FROM
job
WHERE
(
job.jobbusiness = 0
AND job.jobfixedstartdate = 1
AND job.jobfixedenddate = 1
AND job.jobenddate <= CURDATE()
))
UNION
DISTINCT (SELECT
job.jobunique AS job_jobunique,
job.jobtypeunique AS job_jobtypeunique,
job.joblat AS job_joblat,
job.joblng AS job_joblng
FROM
job
WHERE
(job.jobbusiness = 0
AND job.jobfixedstartdate = 1
AND job.jobfixedenddate = 0
AND job.jobstartdate >= CURDATE()))
UNION
DISTINCT (SELECT
job.jobunique AS job_jobunique,
job.jobtypeunique AS job_jobtypeunique,
job.joblat AS job_joblat,
job.joblng AS job_joblng
FROM
job
WHERE
(job.jobbusiness = 0
AND job.jobfixedstartdate = 0
AND job.jobfixedenddate = 0
AND job.jobdateadded >= (CURDATE() - INTERVAL 60 DAY)))
UNION
DISTINCT (SELECT
job.jobunique AS job_jobunique,
job.jobtypeunique AS job_jobtypeunique,
job.joblat AS job_joblat,
job.joblng AS job_joblng
FROM
job
WHERE
job.jobdeleted = 0
AND job.jobpayed = 1
AND (LOWER(job.jobtitle) LIKE '%taxi%'
OR LOWER(job.jobmaincategory) LIKE '%taxi%'
OR LOWER(job.jobsubcategory) LIKE '%taxi%'
OR LOWER(job.jobdescription) LIKE '%taxi%'
OR LOWER(job.jobcountry) LIKE '%taxi%')
AND (job.jobbusiness = 1
AND job.jobstartdate <= CURDATE()
AND job.jobenddate >= CURDATE()))
) AS union1