Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 我可以避免在这个查询中重复计算吗?_Mysql_Performance_Optimization - Fatal编程技术网

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函数呢?