我试图获取每页5个作业的结果(我使用带有doctrine的silex),但页面加载大约需要30-40秒。
$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);
答案 0 :(得分:1)
正确的索引通常是数据库设计良好时的解决方案。但在您的情况下,我在查询构造中看到(可能的)问题。由于我不是MySQL专家,我认为其他用户可能会证实我的怀疑。
实际上,你加入了 ALL 与(显然)ONE to MANY关系中的其他表的作业,这可能会产生更大的结果集ORDER BY
只是为了获得前五个记录最近才加入。
我认为您应该在WHERE
子句中过滤掉第一个最相关的工作,以减少JOIN
和ORDER BY
处理。试试这段代码:
WHERE jobs.id IN (SELECT id FROM jobs ORDER BY date_added DESC LIMIT 5)
并检查您要加入的外键列和“date_added”列是否具有正确的索引。
答案 1 :(得分:1)
执行计划显示只使用了两个(主键)索引。这应该改进。除主键索引外,您还应尝试使用额外的索引:
查询可能也会因子查询而变慢,该查询具有特殊的LIMIT 1
。这意味着它检索的记录可能是几个中的随机记录。这或者意味着您的数据库设计需要,或者您不关心显示附件表的所有相关记录。使用不IN (SELECT ...)
的{{1}}可确保您获得所有附件记录。
但是比使用LIMIT
更好,将其转换为额外的IN
,如下所示:
JOIN
另一个特殊的事情: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
或者引用usersmeta.parent_id
或jobs.ID
值。这看起来像您可能想要查看的数据库设计中的另一个缺陷。
如果'job.id'值的顺序与jobs.user
的顺序相同,那么您可以考虑执行jobs.date_added
。如果没有,请考虑在ORDER BY jobs.id DESC
上创建索引。
最后,您的jobs(date_added)
不够具体,因为它允许共享相同order by
的记录的任意排序顺序。这与性能无关,但我预计它会使分页变得困难(取决于你如何实现它)。最好的方法是,如果您可以在jobs.id
子句中列出的列组合在一起唯一地标识结果中的记录。
答案 2 :(得分:0)
您可以启用mysql查询缓存以加快重复查询。