问题
I have very big database of customers. This query was ok before I added ORDER BY
. How can I optimize my query speed?
$sql = "SELECT * FROM customers LEFT JOIN ids ON customer_ids.customer_id = customers.customer_id AND ids.type = '10' ORDER BY customers.name LIMIT 10";
ids.type
and customers.name
are my indexes
Explain query
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE customers ALL NULL NULL NULL NULL 955 Using temporary; Using filesort 1 SIMPLE ids ALL type NULL NULL NULL 3551 Using where; Using join buffer (Block Nested Loop)
回答1:
(I assume you meant to type ids.customer_id = customer.customer_id
and not customer_ids.customer_id)
Without the ORDER BY mysql grabbed the first 10 ids of type 10 (indexed), looked up the customer for them, and was done. (Note that the LEFT JOIN here is really an INNER JOIN because the join conditions will only hold for rows that have a match in both tables)
With the ORDER BY mysql is probably retrieving all type=10 customers then sorting them by first name to find the first 10.
You could speed this up by either denormalizing the customers table (copy the type into the customer record) or creating a mapping table to hold the customer_id, name, type
tuples. In either case, add an index on (type, name)
. If using the mapping table, use it to do a 3-way join with customers and ids.
If type=10 is reasonably common, you could also force the query to walk the customers table by name and check the type for each with STRAIGHT JOIN. It won't be as fast as a compound index, but it will be faster than pulling up all matches.
And as suggested above, run an EXPLAIN on your query to see the query plan that mysql is using.
回答2:
LEFT is the problem. By saying LEFT JOIN, you are implying that some customers
may not have a corresponding row(s) in ids
. And you are willing to accept NULLs for the fields in place of such an ids
row.
If that is not the case, then remove LEFT. Then make sure you have an index on ids
that starts with type
. Also, customers
must have an index (probably the PRIMARY KEY
) starting with customer_id
. With those, the optimizer can start with ids
, filter on type
earlier, thereby have less work to do.
But, still, it must collect lots of rows before doing the sort (ORDER BY
); only then can it deliver the 10 (LIMIT
).
While you are at it, add INDEX(customer_id)
to ids
-- that is what is killing performance for the LEFT version.
来源:https://stackoverflow.com/questions/28390181/why-is-this-inner-join-order-by-mysql-query-so-slow