Reputation: 1
I'm struggling with the following sql query to display a search result from a mysql db
This works
SELECT
*
FROM
lagerbestand
LEFT JOIN
verkaufspreis USING (materialnummer)
WHERE
lagerbestand.level='2' AND (lagerbestand.materialnummer='$suche' OR lagerbestand.materialkurztext LIKE '%$suche%')
This works too
SELECT
*
FROM
lagerbestand
LEFT JOIN
verkaufspreis USING (materialnummer)
WHERE
lagerbestand.materialnummer='$suche' OR verkaufspreis.bezeichnung_fr LIKE '%$suche%'
But this doesn't work
SELECT
*
FROM
lagerbestand
LEFT JOIN
verkaufspreis USING (materialnummer)
WHERE
lagerbestand.level='2' AND (lagerbestand.materialnummer='$suche' OR verkaufspreis.bezeichnung_fr LIKE '%$suche%')
The only difference is the last bit.
lagerbestand.materialkurztext is changed to verkaufspreis.bezeichnung_fr
Then the script just loads for ever.
Upvotes: 0
Views: 73
Reputation: 1269753
I would start by using indexes to speed the query. Also, drop the quotes from 2
if it is not necessary:
SELECT *
FROM lagerbestand l LEFT JOIN
verkaufspreis v
USING (materialnummer)
WHERE l.level = 2 AND (l.materialnummer = '$suche' OR v.materialnummer LIKE '%$suche%');
For this query, you want an index on lagerbestand(level, bezeichnung_fr)
and verkaufspreis(materialnummer, bezeichnung_fr)
.
I'm not guaranteeing this will result in great performance, but it is a place to start.
EDIT:
OR
can be hard to optimize for a query. The next idea is to use union all
:
SELECT *
FROM lagerbestand l LEFT JOIN
verkaufspreis v
USING (materialnummer)
WHERE l.level = 2 AND l.materialnummer = '$suche'
UNION ALL
SELECT *
FROM lagerbestand l JOIN
verkaufspreis v
USING (materialnummer)
WHERE l.level = 2 AND (l.materialnummer <> '$suche' AND v.materialnummer LIKE '%$suche%');
This might be faster, because the subqueries might be optimized more efficiently. You can try each one independently to see if there still a performance problem.
Upvotes: 1
Reputation: 108400
If I wanted to return set specified in the last query, I think the best bet for optimal performance is going to be to break that up into two distinct sets, and combine those with a UNION ALL set operator.
(If $such
is meant to be variable that is substituted into the SQL text, I would make sure that it has been properly escaped, before it is included.)
SELECT l.*, v.*
FROM lagerbestand l
LEFT JOIN verkaufspreis v USING (materialnummer)
WHERE l.level = '2'
AND l.materialnummer = '$suche'
UNION ALL
SELECT l.*, v.*
FROM lagerbestand l
JOIN verkaufspreis v USING (materialnummer)
WHERE l.level = '2'
AND NOT ( l.materialnummer <=> '$suche' )
AND v.bezeichnung_fr LIKE CONCAT('%','$suche','%')
Then I would tune each of those SELECT separately, using EXPLAIN
, making sure appropriate indexes are available.
ON verkaufspreis (materialnummer, bezeichnung_fr, ... )
ON lagerbestand (level, materialnummer, ... )
Upvotes: 0