简体   繁体   中英

Turn a Mysql Subquery in a Join

How can I turn this subquery in a JOIN ?

I read that subqueries are slower than JOIN s.

SELECT 
    reklamation.id, 
    reklamation.titel,
    ( 
        SELECT reklamation_status.status 
        FROM reklamation_status 
        WHERE reklamation_status.id_reklamation = reklamation.id 
        ORDER BY reklamation_status.id DESC 
        LIMIT 1 
    ) as status
FROM reklamation 
WHERE reklamation.aktiv=1

Using JOIN query can be rewritten to:

SELECT reklamation.id, reklamation.titel, reklamation_status.status
FROM reklamation 
JOIN reklamation_status ON reklamation_status.id_reklamation = reklamation.id
WHERE reklamation.aktiv=1

This should do it:

SELECT r.id, r.titel, MAX(s.id) as status
FROM reklamation r
LEFT JOIN reklamation_status s ON s.id_reklamation = r.id
WHERE r.aktiv = 1   
GROUP BY r.id, r.titel

The key point here is to use aggregation to manage the cardinality between reklamation and reklamation_status . In your original code, the inline subquery uses ORDER BY reklamation_status.id DESC LIMIT 1 to return the highest id in reklamation_status that corresponds to the current reklamation . Without aggregation, we would probably get multiple records in the resultset for each reklamation (one for each corresponding reklamation_status ).

Another thing is to consider is the type of the JOIN . INNER JOIN would filter out records of reklamation s that do not have a reklamation_status : the original query with the inline subquery does not behave like that, so I chose LEFT JOIN . If you can guarantee that every reklamation has at least one child in reklamation_status , you can safely switch back to INNER JOIN (which might perform more efficiently).


PS:

I read that subqueries are slower than JOIN s.

This is not a universal truth. It depends on many factors and cannot be told without seeing your exact use case.

What you read is incorrect. Subqueries can be slower, faster, or the same as joins. I would write the query as:

SELECT r.id, r.titel,
       (SELECT rs.status 
        FROM reklamation_status rs
        WHERE rs.id_reklamation = r.id 
        ORDER BY rs.id DESC 
        LIMIT 1 
       ) as status
FROM reklamation  r
WHERE r.aktiv = 1;

For performance, you want an index on reklamation_status(id_reklamation, id, status) .

By the way, this is a case where the subquery is probably the fastest method for expressing this query. If you attempt a JOIN , then you need some sort of aggregation to get the most recent status. That can be expensive.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM