Consider the following query:
SELECT
`locations`.`id` AS `location_id`,
`locations`.`address`,
`locations`.`lat`,
`locations`.`lng`,
`tickets`.`status_id`,
`customers`.`name`,
`tickets`.`id` AS `id`,
`tickets`.`updated_at` AS `updated_at`,
( 3959 * acos( cos( radians('39.78222851322262') ) * cos( radians( `lat` ) ) * cos( radians( `lng` ) - radians('-86.16299560000004') ) + sin( radians('39.78222851322262') ) * sin( radians( `lat` ) ) ) ) AS `distance`
FROM `locations`
RIGHT JOIN `tickets`
ON (`tickets`.`location_id` = `locations`.`id`)
LEFT JOIN `customers`
ON (`tickets`.`customer_id` = `customers`.`id`)
WHERE `tickets`.`client_id` = '20'
AND
(
`customers`.`name` LIKE '%Mahoney%'
OR `customers`.`email` LIKE '%Mahoney%'
OR `locations`.`address` LIKE '%Mahoney%'
)
HAVING `distance` < '5'
ORDER BY `distance`
LIMIT 200;
Using a profiling tool, I got this report:
Speed: 45.569 ms
Query analysis:
· Query: SIMPLE on tickets · Type: ALL · Rows: 160 (Using where; Using temporary; Using filesort)
· Query: SIMPLE on locations · Possible keys: PRIMARY · Key Used: PRIMARY · Type: eq_ref · Rows: 1
· Query: SIMPLE on customers · Possible keys: PRIMARY · Key Used: PRIMARY · Type: eq_ref · Rows: 1 (Using where)
This is a MySQL database. All the tables are InnoDB with utf8_unicode_ci. The primary keys on each table are called id
and are int(11)
with indexes on them.
- Should adding an index on
tickets.location_id
and/ortickets.customer_id
and/ortickets.client_id
improve performance of this query at all? - Why or why not?
- Are there any other fields I should consider indexing to improve the efficiency of this query?
- Should I be explicitly defining my foreign keys in my database schema?
My thinking is that since I'm selecting from locations first, I would want an index on the foreign keys that are being referenced. I read here: indexes, foreign keys and optimization that MySQL requires indexes on all foreign keys. Does explicitly defining the foreign keys in an InnoDB schema improve performance? Sorry for being such a total n00b. Thanks for the help!
lat
andlng
of thelocations
table and then search a 'box' around your search radius. Simply find the highest and lowest possible values forlat
andlng
each and addlocations.lat <= :max_lat
, etc, to your query. With that, you will greatly narrow the number of records looked at as determined by location.