我尝试优化我的MySQL查询,我已经将所有表合并到一个表似乎有用的表。
但查询仍需要2秒钟......有没有办法让它更快?
在user_id上始终是索引。 MySQL 5.5.12,除城市外的所有表都是InnoDB表。
SELECT b.user_id,b.firstname,b.lastname,b.address,b.zipcode,b.city
, ($calculatings) AS Distance
FROM `user_profiles` `b`
LEFT JOIN `cities` `a` ON `a`.`postal`=`b`.`zipcode`
JOIN `users` `u` ON `b`.`user_id`=`u`.`id`
JOIN `user_consultants` `c` ON `b`.`user_id`=`c`.`user_id`
WHERE ($calculatings) <= 25
AND c.incorporated='1'
AND u.typ='1'
AND u.activated='1'
AND u.banned='0'
ORDER BY Distance ASC, c.zsum_score DESC
LIMIT 30
在var $ calculates中是距离计算的数学运算(已经优化)。
$计算示例:
6368 * SQRT(2*(1-cos(RADIANS(`a`.`lat`)) * cos(0.840105508801) *
(sin(RADIANS(`a`.`lon`)) * sin(0.201952047748) + cos(RADIANS(`a`.`lon`)) *
cos(0.201952047748)) - sin(RADIANS(`a`.`lat`)) * sin(0.840105508801)))
为什么这么多左连接?
尺寸
解释SQL (右键单击全尺寸)
答案 0 :(得分:2)
我没有时间写完整的细节,但为了优化空间搜索,这里有一个快速的问题:
将(latitude, longitude)
对存储在(MyISAM)表中作为空间字段:POINT
(GEOMETRY
类型的变体)。
在此字段上添加空间索引。
使用查询中的MBRContains()
或MBRWithin()
函数,使用类似的方法,将使用空间索引缩小包含来自基数的Radius 25的圆的正方形内的搜索范围点:
WHERE MBRWithin( cities.myPointField
, Polygon( @lat-25 @long-25
, @lat+25 @long-25
, @lat+25 @long+25
, @lat-25 @long+25
)
)
AND (yourDistanceCalculation) < 25
您可以查看MySQL文档: Spatial Extensions
答案 1 :(得分:1)
您应该拥有(至少)索引:cities.postal,users.typ,users.activated,users.banned,user_consultants.incorporated
答案 2 :(得分:1)
SELECT
b.user_id,b.firstname,b.lastname,b.address,b.zipcode,b.city,
($calculatings) AS Distance
FROM
`user_profiles` `b`
JOIN `users` `u` ON `b`.`user_id`=`u`.`id`
AND `u`.`typ`=1
AND `u`.`activated`=1
AND `u`.`banned`=0
LEFT JOIN `cities` `a` ON `b`.`zipcode`=`a`.`postal`
LEFT JOIN `user_consultants` `c` ON `b`.`user_id`=`c`.`user_id`
WHERE Distance <= 25
ORDER BY Distance ASC, c.zsum_score DESC
LIMIT 0,30
...虽然,如果$calculatings
的值始终相同且我看到它只取决于表cities
中的数据 - 您应该只在其中放入另一列,包含预先计算的距离值。
关于我所做的改变的一些注释:
typ
,activated
和banned
的类型为int
(通过查询中的值进行猜测) - 您不应将它们放在引号中users
是您的主要用户表,user_id
中的每个user_profiles
都应该在id
中存在users
,所以你不要不需要LEFT
。JOIN
比WHERE
条款快(WHERE
比HAVING
快,因为我看到另一个使用它的答案。)答案 3 :(得分:1)
我认为你会略微偏离它(但可能是错的)。您正在根据用户配置文件开始查询,但您的所有条件都处于用户和用户顾问级别的最低级别。我会做一个STRAIGHT_JOIN(告诉优化器按照你声明的顺序)。然后,在您的连接上,执行LEFT JOIN并不一定有意义,除非您在表之间缺少链接ID值,这将允许某些记录不具有给定的城市或用户配置文件。所以,话虽如此,我会把你的用户表放在前面,因为这可能会通过标准设置最严格的结果集。另外,有一个索引(典型,激活,禁止)。接下来,您的user_consultants表并具有(user_id,合并)的索引。城市应该有邮政索引,user_profiles是邮政编码索引。
这是我要尝试的最终查询
select STRAIGHT_JOIN
b.user_id,
b.firstname,
b.lastname,
b.address,
b.zipcode,
b.city,
($calculatings) AS Distance
from
(select u.id, c.zsum_score
from
users u
join user_consultants c
on u.id = c.user_id
and c.incorporated = '1'
where
u.typ = '1'
and u.activated = '1'
and u.banned = '0' ) PreQuery
join user_profiles b
on PreQuery.ID = b.user_id
join cities a on b.zipcode = a.postal
where
($calculatings) <= 25
ORDER BY
Distance ASC,
PreQuery.zsum_score DESC
LIMIT 30
由于用户和用户顾问之间的连接是用户ID,因此用户顾问和用户配置文件是用户ID,“PreQuery”ID之间的连接是相同的,所以不需要重新连接到BOTH表
答案 4 :(得分:0)
SELECT
b.user_id,b.firstname,b.lastname,b.address,b.zipcode,b.city,
($calculatings) AS Distance
FROM
`user_profiles` `b`
JOIN `cities` `a` ON `a`.`postal`=`b`.`zipcode`
JOIN `users` `u` ON `b`.`user_id`=`u`.`id`
JOIN `user_consultants` `c` ON `b`.`user_id`=`c`.`user_id`
WHERE
c.incorporated='1' AND
u.typ='1' AND
u.activated='1' AND
u.banned='0'
HAVING
Distance <= 25
ORDER BY
Distance ASC, c.zsum_score DESC
LIMIT 30