优化 sql 查询以提高效率
Optimizing an sql query for efficiency
我有一个关于地理距离的查询。查询非常快,在我的 224 万行 table 上大约用了 0.1175 秒返回。但是,我只需要最短的距离,使用内置的order by太慢了。
有什么方法可以跟踪 运行ning 最小值并告诉我吗?
例如,如果我有这些结果:
city a - 45km
city b - 48km
city c - 12km
我可以让它给我 12 公里,记住所有距离值都是计算出来的吗?
这里是排序的查询:
SELECT
City,
(
6371 *
acos(
cos(radians(-60.61384878636903)) *
cos(radians(st_x(location))) *
cos(radians(st_y(location)) -
radians(112.80061386895574)) +
sin(radians(-60.61384878636903)) *
sin(radians(st_x(location))))
) as distance
FROM table_name
HAVING distance < 5
ORDER BY distance ASC LIMIT 1
table结构如下:
id - int(12)
location - Point()
City - varchar(255)
问题在于按标志排序花费的时间太长,无法对数据进行排序并获得最低。它可以只保持 运行ning 最小值,然后在不对性能造成重大影响的情况下给我吗?
table包含,
2227851 - rows
spatial index on location
如果我使用 order by 我得到的 运行 时间大约是 14 秒 如果我不使用 order by 我得到的时间是 .1 秒,这是我想要的 运行或接近
建议:
- 更好的性能来自使用 MySql spatial functions 和索引
但如果你不想使用它
- 预计算常量
Set A = cos(radians(-60.61384878636903))
cos 函数非常慢。
- 过滤您的示例数据。如果您的原点是
X,Y
,您可以创建一个正方形 X +- 5, Y +- 5
并在 X,Y
上使用常规索引
不,确实没有办法在查询级别保持 运行 最小值。
基本问题是最小距离对于不同的纬度和经度值是不同的,搜索坐标在查询中作为文字提供。
一个选项是保留 table 以前的搜索坐标,即您之前查找过的坐标,然后使用它来缩短执行另一个查询的需要。首先搜索以前搜索的table,然后从那里得到结果。
当然,如果您向 table_name
添加一行,您可能需要根据新行重新评估保存的搜索坐标,并确定新行的距离是否比什么更短你已经保存了。 (或者只是使整个商店无效,并为您进行的每次搜索重新填充。)
基本问题是必须对 table_name
中的每一行计算 "great-circle distance" 表达式。
对于不同的搜索值,该表达式的结果会有所不同
(纬度和经度)。
无法避免对每一行进行计算,并从所有这些结果中找到最低值。那将是一个 "Using filesort" 操作。使用 LIMIT 1,我们希望 MySQL 不必对整个集合进行排序,它只需通过一次即可确定最小值。
如果您可以限制 table_name
中需要评估的行数,并且可以使用索引有效地排除它们...那将加快查询速度。
限制行数的一种方法是根据搜索纬度和经度定义 "bounding box"。并在 WHERE 子句中指定。并让 MySQL 使用适当的索引。最粗略的边界框可以定义为搜索坐标的 +/-dx 纬度和 +/-dy 经度...例如
WHERE t.lat BETWEEN -60.613848 -4 AND -60.613848 +4
AND t.lon BETWEEN 120.800613 -8 AND 120.800613 +8
这不是一个理想的边界框,因为经度在赤道的距离比在两极附近的距离要长得多。
至于保持 "running minimum"... 您当前的查询无法完成。如果没有以某种方式键入搜索参数的其他数据存储,则无法完成此操作。
我有一个关于地理距离的查询。查询非常快,在我的 224 万行 table 上大约用了 0.1175 秒返回。但是,我只需要最短的距离,使用内置的order by太慢了。
有什么方法可以跟踪 运行ning 最小值并告诉我吗?
例如,如果我有这些结果:
city a - 45km
city b - 48km
city c - 12km
我可以让它给我 12 公里,记住所有距离值都是计算出来的吗?
这里是排序的查询:
SELECT
City,
(
6371 *
acos(
cos(radians(-60.61384878636903)) *
cos(radians(st_x(location))) *
cos(radians(st_y(location)) -
radians(112.80061386895574)) +
sin(radians(-60.61384878636903)) *
sin(radians(st_x(location))))
) as distance
FROM table_name
HAVING distance < 5
ORDER BY distance ASC LIMIT 1
table结构如下:
id - int(12)
location - Point()
City - varchar(255)
问题在于按标志排序花费的时间太长,无法对数据进行排序并获得最低。它可以只保持 运行ning 最小值,然后在不对性能造成重大影响的情况下给我吗?
table包含,
2227851 - rows
spatial index on location
如果我使用 order by 我得到的 运行 时间大约是 14 秒 如果我不使用 order by 我得到的时间是 .1 秒,这是我想要的 运行或接近
建议:
- 更好的性能来自使用 MySql spatial functions 和索引
但如果你不想使用它
- 预计算常量
Set A = cos(radians(-60.61384878636903))
cos 函数非常慢。 - 过滤您的示例数据。如果您的原点是
X,Y
,您可以创建一个正方形X +- 5, Y +- 5
并在X,Y
上使用常规索引
不,确实没有办法在查询级别保持 运行 最小值。
基本问题是最小距离对于不同的纬度和经度值是不同的,搜索坐标在查询中作为文字提供。
一个选项是保留 table 以前的搜索坐标,即您之前查找过的坐标,然后使用它来缩短执行另一个查询的需要。首先搜索以前搜索的table,然后从那里得到结果。
当然,如果您向 table_name
添加一行,您可能需要根据新行重新评估保存的搜索坐标,并确定新行的距离是否比什么更短你已经保存了。 (或者只是使整个商店无效,并为您进行的每次搜索重新填充。)
基本问题是必须对 table_name
中的每一行计算 "great-circle distance" 表达式。
对于不同的搜索值,该表达式的结果会有所不同 (纬度和经度)。
无法避免对每一行进行计算,并从所有这些结果中找到最低值。那将是一个 "Using filesort" 操作。使用 LIMIT 1,我们希望 MySQL 不必对整个集合进行排序,它只需通过一次即可确定最小值。
如果您可以限制 table_name
中需要评估的行数,并且可以使用索引有效地排除它们...那将加快查询速度。
限制行数的一种方法是根据搜索纬度和经度定义 "bounding box"。并在 WHERE 子句中指定。并让 MySQL 使用适当的索引。最粗略的边界框可以定义为搜索坐标的 +/-dx 纬度和 +/-dy 经度...例如
WHERE t.lat BETWEEN -60.613848 -4 AND -60.613848 +4
AND t.lon BETWEEN 120.800613 -8 AND 120.800613 +8
这不是一个理想的边界框,因为经度在赤道的距离比在两极附近的距离要长得多。
至于保持 "running minimum"... 您当前的查询无法完成。如果没有以某种方式键入搜索参数的其他数据存储,则无法完成此操作。