【发布时间】:2021-11-25 00:12:21
【问题描述】:
我有一个复杂的 MySQL 查询,其中包含多个计算和连接,以按位置检索承包商列表。承包商表(用户)包含 100,000 多行并且还在增长。我遇到的问题是查询需要超过 1.5 秒才能执行,这会导致页面加载显着延迟。
我发现去掉 ORDER BY 子句后,速度明显提高(
还值得注意的是,我已按照其他帖子中的建议添加了索引,但我相信您在对计算列进行排序时无法进一步优化。 (如有错误请指正)
这是查询(为简单起见,我删除了几个列和连接,但查询仍然需要相同的时间来执行):
SELECT `users`.`id`,
`users`.`username`,
IF (Max(up.premium_expires_at) > Now(), 1, 0) AS `is_premium`,
IF (users.last_online_at >= Now() - INTERVAL 30 day, 1, 0) AS `recent_login`,
IF (da.id IS NOT NULL, 1, 0) AS `is_available`,
( 3959 * Acos(Cos(Radians(53.80592)) * Cos(Radians(lat)) * Cos(
Radians(lng) - Radians(-1.53834
)) + Sin(Radians(53.80592)) *
Sin(Radians(lat))) ) AS
`distance`
FROM `users`
INNER JOIN `users_places` AS `up`
ON `users`.`id` = `up`.`user_id`
INNER JOIN `places` AS `mp`
ON `users`.`place_id` = `mp`.`id`
LEFT JOIN `users_dates_available` AS `da`
ON `da`.`user_id` = `users`.`id`
AND `from` <= Curdate()
AND `to` >= Curdate()
LEFT JOIN (SELECT user_id,
Sum(score) AS score
FROM users_feedback
WHERE status = 1
GROUP BY user_id) AS feedback
ON `users`.`id` = `feedback`.`user_id`
WHERE `users`.`status` = 1
AND `users`.`approved` = 1
GROUP BY `users`.`id`
HAVING `distance` < 50
ORDER BY `is_premium` DESC,
`recent_login` DESC
LIMIT 5
这是 EXPLAIN 的结果
所以我想我的问题是:在网页上显示这些数据的最快方法是什么?
我的尝试:
-
查询是 Laravel 应用程序的一部分。我尝试在没有 ORDER BY 的情况下运行查询并按 PHP 排序。但是执行时间仍然很慢。
-
在没有左连接的情况下运行查询,我注意到速度有了显着提高。但是,查询必须使用 LEFT 连接来进行 SELECT 条件中的计算(我们正在检查 NULL 值)。
-
使用视图 - 使用预编译视图的查询速度仍然相同。
我能想到的唯一其他选择是创建一个包含所有计算字段的临时表并对其进行查询。但是,这不会存储“距离”列,因为这是特定于运行查询的用户,我仍将按计算列排序。
是否有其他选项或其他方法来优化我缺少的此查询?谢谢
【问题讨论】:
-
也许你可以把它拆分一下,用 PHP 做一些逻辑。就像从 SELECT
users.id,users.usernameWHEREusers.status= 1 ANDusers.approved= 1 开始然后做一些其他简单的 SELECT 语句和 PHP 排序用正确的信息来显示你的数组 -
@Bolli - 但前提是只有极少数行的状态=1 且已批准=1。