I’ve been thinking about this for a while and its got to a point where I think its better to ask around and listen what other people think.
Im bulding a system that stores locations on Mysql. Every location has a type and some locations have multiple addresses.
The tables look something like this
location
- location_id (autoincrement)
- location_name
- location_type_id
location_types
- type_id
- type_name (For example "Laundry")
location_information
- location_id (Reference to the location table)
- location_address
- location_phone
So if i wanted to query the database for the 10 most recently added I would go with something like this:
SELECT l.location_id, l.location_name,
t.type_id, t.type_name,
i.location_address, i.location_phone
FROM location AS l
LEFT JOIN location_information AS i ON (l.location_id = i.location_id)
LEFT JOIN location_types AS t ON (l.location_type_id = t.type_id)
ORDER BY l.location_id DESC
LIMIT 10
Right? But the problem is that if a location has more than 1 address the limit/pagination is not going to be accurrate, unless I “GROUP BY l.location_id”, but that is going to show only one address for each place.. what happens with the places that have multiple addresses?
So I thought the only way to solve this is by doing a query inside a loop.. Something like this (pseudocode):
$db->query('SELECT l.location_id, l.location_name,
t.type_id, t.type_name
FROM location AS l
LEFT JOIN location_types AS t ON (l.location_type_id = t.type_id)
ORDER BY l.location_id DESC
LIMIT 10');
$locations = array();
while ($row = $db->fetchRow())
{
$db->query('SELECT i.location_address, i.location_phone
FROM location_information AS i
WHERE i.location_id = ?', $row['location_id']);
$locationInfo = $db->fetchAll();
$locations[$row['location_id']] = array('location_name' => $row['location_name'],
'location_type' => $row['location_type'],
'location_info' => $locationInfo);
}
Now im getting the last 10 places, but by doing that I wind up with at least 10 queries more, and I dont think that helps the app performance.
Is there a better way to achieve what im looking for? (accurate pagination).
Here is your original query
You perform the pagination last. If you refactor this query, you can perform the pagination earlier.
Notice I created a subquery called
k. The 10 keys get picked up and ordered FIRST !!!Then the JOINs can go on from there, hope using just 10 location_ids.
What will help the subquery
kis an index that carries location_id and location_type_idHere is something else you may like about this approach
How do you query for the next 10 ids (ids 11 – 20) ? Like this:
All you have to do is change the
LIMITclause in subquerykwith each new page.LIMIT 20,10LIMIT 30,10I can improve the refactoring by removing the location table and have subquery k carry the needed fields like this:
Making that extra index would not be necessary for this version.
Give it a Try !!!