Mysql 我可以避免在这个查询中重复计算吗?
要匹配靠近经纬度的点Mysql 我可以避免在这个查询中重复计算吗?,mysql,performance,optimization,Mysql,Performance,Optimization,要匹配靠近经纬度的点(point_lat,point_lon),我需要这样做 SELECT id, lat, lon, ACOS(COS(RADIANS(ABS(lat - point_lat))) * COS(RADIANS(IF(ABS(lon - point_lon) > 180, 360 - ABS(lon - point_lon), ABS(lon - point_lon))))) as angle_between FROM places; 查询的IF(ABS(lon-poin
(point_lat,point_lon)
,我需要这样做
SELECT id, lat, lon,
ACOS(COS(RADIANS(ABS(lat - point_lat))) * COS(RADIANS(IF(ABS(lon - point_lon) > 180, 360 - ABS(lon - point_lon), ABS(lon - point_lon))))) as angle_between
FROM places;
查询的IF(ABS(lon-point_-lon)>180,360-ABS(lon-point_-lon),ABS(lon-point_-lon))
部分真的很伤我的眼睛,看起来像ABS(lon-point_-lon)
计算了2次,除非MySQL在内部优化IF
places
表相当大(约600万行),因此我希望尽可能高效地执行此操作。你有什么建议吗
编辑:ABS(lon-point_-lon)
计算起来并不昂贵,我知道这一点。但事实上,我在查询中选择的angle\u-between
需要像angle\u-between=IF(angle\u-between>180,360-angle\u-between,angle\u-between)
和计算angle\u-between
非常昂贵。
我知道我可以使用派生表,查询变成:
SELECT t.id, t.lat, t.lon, t.angle_between, if(t.angle_between > 180, 360 - angle_between, angle_between) as angle FROM (
SELECT id, lat, lon,
ACOS(COS(RADIANS(ABS(lat - point_lat))) * COS(RADIANS(IF(ABS(lon - point_lon) > 180, 360 - ABS(lon - point_lon), ABS(lon - point_lon))))) as angle_between
FROM places
) AS t
ORDER BY angle LIMIT 20;
“自定义MySQL函数”似乎也是一种选择,但我对它们的性能不太确定。我不会担心为ABS(lon-point_-lon)
计算花费的时间。这应该是计算的一小部分,尤其是在使用三角函数时。事实上,对于大多数查询,访问数据所花费的时间在查询中占主导地位;而不是花在运行函数上的时间。情况并非总是如此,但在您的查询中,ACOS()
和其他函数将花费更多时间
如果不需要显式的If()
,还可以使用:
greatest(ABS(lon - point_lon), 360 - ABS(lon - point_lon))
编辑:
在您的特定情况下,您可以:
IF( (@x := ABS(lon - point_lon)) > 180, 360 - @x, @x)
这只能保证有效,因为所有逻辑都在一个语句中(这就是为什么我没有首先提出它)。MySQL不保证select
子句中表达式的求值顺序,因此您不应该在任何其他表达式中使用@x
其他选项(如使用子查询或union all
)需要读取和写入更多数据。这是提高性能的一个高门槛(您可以随时测试替代方案,看看它们是否工作得更好,只是不要太乐观)。换句话说,没有真正好的解决方案,尽管变量方法可能最适合您的特定情况。ABS(lon-point_-lon)
只是一个例子。。。有些情况下,值是一个包含5-6个触发器函数的巨大表达式。。。我知道我可以使用派生表,但不确定性能…@Optimus。在MySQL中,派生表将产生具体化表的开销。这可能比计算更昂贵。那么自定义mysql函数呢?