MySQL sorting over multiple tables takes very long
I have a table with objects and related tables object_info, object_theme (category), locations and the object owners.
What I want is showing all objects from object owners with a higher priority first, and then the rest. So my query is something like the following:
SELECT
(...)
FROM objects
INNER JOIN object_info ...
INNER JOIN objectowner_info ...
INNER JOIN locations ...
WHERE object_active = 1
AND object_owner_active = 1
ORDER BY object_owner_priority DESC,
object_price ASC
LIMIT 0, 10
As you can see I select all objects and giving the ones from object owners with a higher priority status the edge of showing first. And then sorting from lowest price up. But most of the time this query is extremely slow.
What are the best steps to optimize this query? I've tried all sorts of indexes, but the bottleneck seems to be the sorting. When I take that o开发者_如何学Cut the query is OK speed-wise.
(Please note I didn't join the themes (categories), I'm thinking of implementing this differently because of the 1:n relations you'll need to group the result as well, and that seems awfully slow. All other tables mentioned in the join have a 1:1 relationship.).
To compare: a query without both columns in sorting takes 0.0011 seconds. The one mentioned above with both columns 0.8779. But depending on the load it could take even seconds.
EXPLAIN with sorting:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE o ALL PRIMARY,fk_object_user,fk_object_city,type active NULL NULL NULL 63773 Using where; Using temporary; Using filesort
1 SIMPLE ooi ref fk_objectowner_id fk_objectowner_id 4 o.object_user 1 Using where
1 SIMPLE oo eq_ref PRIMARY,id_and_status PRIMARY 4 o.object_user 1 Using where
1 SIMPLE l eq_ref PRIMARY PRIMARY 4 o.object_city 1 Using where
1 SIMPLE oi ref fk_info_lang,fk_info_object,lang_object fk_info_object 3 o.object_id 1 Using where
EXPLAIN without sorting:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE o ALL PRIMARY,fk_object_user,fk_object_city,type active NULL NULL NULL 63773 Using where
1 SIMPLE ooi ref fk_objectowner_id fk_objectowner_id 4 o.object_user 1 Using where
1 SIMPLE oo eq_ref PRIMARY,id_and_status PRIMARY 4 o.object_user 1 Using where
1 SIMPLE l eq_ref PRIMARY PRIMARY 4 o.object_city 1 Using where
1 SIMPLE oi ref fk_info_lang,fk_info_object,lang_object fk_info_object 3 o.object_id 1 Using where
Define indexes on object_owner_priority and object_price, and change the where clause to something like:
WHERE object_active + 0 = 1
AND object_owner_active + 0 = 1
With any luck that should do the trick. If you have defined indexes on object_active or object_owner_active, consider deleting them.
Well, problem is now solved by creating separate order columns and filling them through a cron job that executes the slow query every once-in-a-while to generate the wanted order.
精彩评论