Reputation: 5852
Here is a mysql query that take about 1ms to complete:
SELECT SQL_NO_CACHE DISTINCT invoice.*,
GROUP_CONCAT(DISTINCT line.guid) as line
FROM invoice
LEFT JOIN ligne ON line.invoice = invoice.guid
GROUP BY invoice.guid
WHERE acompte = 1
LIMIT 0, 100;
If I add ORDER BY invoice.date
to the query, it become really slow and take about 3s to complete.
If I remove the LEFT JOIN
(and the GROUP_CONCAT
) the query take again 1ms.
I've add EXPLAIN
to see what MySQL is doing when the query is slow, and I can see that it's using a temporary file:
1 SIMPLE invoice index NULL PRIMARY 4 NULL 25385 Using temporary; Using filesort
1 SIMPLE line ref invoice invoice 5 gestixi.invoice.guid 1 Using index
I'm sure there is a way to speed up that query but I can't find it. Any idea ?
Note that I can't add an index on date
(which by the way don't change anything) because I want my users to be able to sort each field of the table.
Also note that invoice.guid
, line.invoice
, line.guid
and acompte
are indexed.
If I do a first query without the LEFT JOIN but with the ORDER BY clause to get the ids of the lines I want, and then a second query (like the one above) using these id in the WHERE clause, I can get what I need in less than 10ms.
This make me believe that it must be a way to speed up that query without adding indexes.
Upvotes: 3
Views: 364
Reputation: 29749
I am afraid that if you must allow your users to sort on any field (and have this sort use an index) then you need an index for each possible sort. It is impossible to do otherwise by definition. Sorting on a given row may only make use of an index on this row.
I see little alternatives here. Either reduce the number of rows to be sorted (25k lines is a bit large a result set, do your users really need that many lines?) or do not allow sorts on all rows.
Notice that a query will usually not be able to use more than one index by table. As advised by others, a compound index is better for the query you mentionned, although I would rather advise the opposite order ((guid, date)
) (the query first needs to select each guid
, and then, for each of them, sort the corresponding rows).
Also add an index on line(guid, acompte, invoice)
.
(above suggestions on indexing assume MyISAM tables)
In terms of optimisation of the query itself, there is little moreto be done, considering the simple execution plan.
You might get better results with this version, or you might not:
SELECT
invoice.*, -- DISTINCT is redudant here because of the GROUP BY clause
GROUP_CONCAT(ligne_acompte.guid) as line -- DISTINCT is (presumably) redundant here because guid is (presumably) unique
FROM invoice
LEFT JOIN (
SELECT guid, invoice
FROM line
WHERE acompte = 1
) AS ligne_acompte ON ligne_acompte.invoice = invoice.guid
GROUP BY invoice.guid
ORDER BY invoice.date;
Upvotes: 1