问题
I have a database that stores "themes" and every theme is associated with a whole bunch of images (=screenshots of these themes). Now I want to display the latest 10 themes and for every theme I only want to get one single image from the database (the one with the lowest ID).
Currently my query looks like this (I am using a subquery):
SELECT DISTINCT
t.theme_id, t.theme_name, theme_date_last_modification, image_id, image_type
FROM
themes t, theme_images i
WHERE
i.theme_id = t.theme_id
AND t.theme_status = 3
AND t.theme_date_added < now( )
AND i.image_id = (
SELECT MIN( image_id )
FROM theme_images ii
WHERE ii.theme_id = t.theme_id
)
GROUP BY
t.theme_id
ORDER BY
t.theme_date_last_modification DESC
LIMIT 10
It works, but the query is very slow. When I use EXPLAIN I can see that there's a "dependent subquery". Is it possible to convert this dependent subquery into some kind of join that can be processed faster by mysql?
P.S.: My actual query is much more complex and makes use of more tables. I have already tried to simplify it as much as possible so that you can concentrate on the actual reason for the performance-problems.
EDIT: This is the output of EXPLAIN:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t index PRIMARY,themes themes 212 NULL 5846 Using where; Using index; Using temporary; Using filesort
1 PRIMARY i eq_ref PRIMARY,theme_id,image_id PRIMARY 4 func 1 Using where
2 DEPENDENT SUBQUERY ii ref theme_id theme_id 4 themes.t.theme_id 6
回答1:
Try this query firstly -
SELECT
t.*, ti1.*
FROM
themes t
JOIN theme_images ti1
ON ti1.theme_id = t.theme_id
JOIN (SELECT theme_id, MIN(image_id) image_id FROM theme_images GROUP BY theme_id) ti2
ON ti1.theme_id = ti2.theme_id AND ti1.image_id = ti2.image_id
ORDER BY
t.theme_date_last_modification DESC
LIMIT 10
One more solution -
SELECT
t.*, ti.*
FROM
themes t
JOIN (SELECT * FROM theme_images ORDER BY image_id) ti
ON ti.theme_id = t.theme_id
GROUP BY
theme_id
ORDER BY
t.theme_date_last_modification DESC
LIMIT
10
Then add your WHERE filter.
回答2:
One approach is to first LIMIT
on the themes
table, then JOIN
to images
:
SELECT
t.theme_id, t.theme_name, t.theme_date_last_modification,
ti.image_id, ti.image_type
FROM
( SELECT theme_id, theme_name, theme_date_last_modification
FROM themes t
WHERE theme_status = 3
AND theme_date_added < now( )
ORDER BY
theme_date_last_modification DESC
LIMIT 10
) AS t
JOIN -- LEFT JOIN if you want themes without an image
theme_images AS ti -- to be shown
ON ti.theme_id = t.theme_id
AND ti.image_id =
( SELECT ii.image_id
FROM theme_images AS ii
WHERE ii.theme_id = t.theme_id
ORDER BY ii.image_id
LIMIT 1
)
ORDER BY
t.theme_date_last_modification DESC ;
With an index on themes (theme_status, theme_date_last_modification, theme_id, theme_date_added)
the limit subquery should be efficient.
I suppose you also have a (unique) index on theme_images (theme_id, image_id)
.
来源:https://stackoverflow.com/questions/18762405/how-to-convert-dependent-subquery-to-join-for-better-performance