I'm trying to fetch 5 results of jobs per page (I'm using silex with doctrine), but the page takes about 30-40 seconds to load.
$sql = "
SELECT jobs.ID, jobs.date_added, jobs.user, jobs.title, jobsmeta.meta_value, jobs_locations_rel.county, jobs_locations_rel.city, usersmeta.meta_value, attachments.title
FROM jobs
JOIN jobsmeta
ON jobsmeta.parent_id = jobs.ID
JOIN jobs_locations_rel
ON jobs_locations_rel.parent_id = jobs.ID
JOIN usersmeta
ON usersmeta.parent_id = jobs.user
JOIN attachments
ON attachments.ID = (SELECT meta_value FROM usersmeta WHERE parent_id = jobs.ID AND meta_key = 'user_avatar' LIMIT 1)
ORDER BY jobs.date_added DESC LIMIT 5";
$data = $app['db']->fetchAll($sql);
This would be the explain plan : How could I optimize this query to get the result in a shorter time?
Correct indexing generally is the solution when your database is well designed. But in your case I see a (possible) problem in the query construction. As I'm not a MySQL expert, I think that other users may confirm my suspicion.
Actually, you join the jobs with other tables in an (apparently) ONE to MANY relationship, which might produce a bigger result set to ORDER BY
just to get the first five records added most recently. 作业与(显然)“一对多”关系中的其他表结合在一起,这可能会产生更大的结果集ORDER BY
只是为了获取最近添加的前五个记录。
I think you should filter in the WHERE
clause the first most relevant jobs to reduce the JOIN
and ORDER BY
processing. Try it including this piece of code:
WHERE jobs.id IN (SELECT id FROM jobs ORDER BY date_added DESC LIMIT 5)
And check that the foreign key columns you are joining and the "date_added" column have proper index.
The execution plan shows that only two (primary key) indexes are used. This should be improved. Apart from the primary key indexes, you should try with extra indexes on:
The query is probably also slowed down by the sub-query, which has a peculiar LIMIT 1
. This means that the record it retrieves might be a random one of several. This either means your database design is wanting, or that you don't care to show all related records of the attachments table. Using IN (SELECT ...)
without LIMIT
would make sure you got all those attachments records.
But better than using IN
, is turning this into an additional JOIN
, like this:
SELECT jobs.ID, jobs.date_added, jobs.user, jobs.title,
jobsmeta.meta_value,
jobs_locations_rel.county, jobs_locations_rel.city,
m1.meta_value, attachments.title
FROM jobs
JOIN jobsmeta
ON jobsmeta.parent_id = jobs.ID
JOIN jobs_locations_rel
ON jobs_locations_rel.parent_id = jobs.ID
JOIN usersmeta m1
ON m1.parent_id = jobs.user
JOIN usersmeta m2
ON m2.parent_id = jobs.ID
AND m2.meta_key = 'user_avatar'
JOIN attachments
ON attachments.ID = m2.meta_value
ORDER BY jobs.date_added DESC
LIMIT 5
Another peculiar thing: usersmeta.parent_id
either references a jobs.ID
or a jobs.user
value. This looks like another flaw in the database design you might want to look at.
If the order of 'job.id' values is the same as the order of jobs.date_added
then you could consider doing an ORDER BY jobs.id DESC
. If not, then consider creating an index on jobs(date_added)
.
Finally, your order by
is not specific enough, as it allows an arbitrary sort order for records that share the same jobs.id
. This is not related to performance, but I expect it could make paging difficult (depending on how you have implemented it). The best would be if you could have a combination of columns listed in the ORDER BY
clause that together uniquely identify the record in the result.
您可以启用mysql查询缓存,以实现更快的重复查询。
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.