如何优化复杂计算查询的执行时间?
Posted
技术标签:
【中文标题】如何优化复杂计算查询的执行时间?【英文标题】:How to optimize complex calculation query execution time? 【发布时间】:2021-01-01 06:22:01 【问题描述】:我有一个这样的查询:
SELECT *, (
6371 * acos (
cos ( radians(33.577718) )
* cos( radians( `Latitude` ) )
* cos( radians( `Longitude` ) - radians(115.846524) )
+ sin ( radians(33.577718) )
* sin( radians( `Latitude` ) )
)
) AS `distance`
FROM `geopc_cn_places_grouped`
WHERE `Latitude`!=33.577718 AND `Longitude`!=115.846524
HAVING `distance` < 200
ORDER BY `distance` ASC
LIMIT 30;
查询执行时间总是在 3.5 到 4 秒之间。
我已经通过运行ALTER TABLE geopc_cn_places_grouped ADD INDEX index_Longitude_Latitude(Longitude, Latitude);
对Latitude
和Longitude
应用了复合索引,但它并没有减少执行时间。
我想知道它为什么运行缓慢以及可以进行哪些优化。
慢查询日志消息显示了这一点
这是EXPLAIN SELECT
查询
表结构...
最后,这里是表格索引列表
【问题讨论】:
研究在 mysql 上创建地理空间索引:dev.mysql.com/doc/refman/8.0/en/creating-spatial-indexes.html 好的,现在检查... 不要使用公式 - 使用空间数据类型和 ST_Distance() 函数。 知道了,谢谢,我正在研究中 警告:latitude != ...
可能由于舍入错误而无法正常工作。考虑使用id
的地方来避免。
【参考方案1】:
您所写的查询不是sargable。也就是说,它不能利用任何索引。所以,每次你运行它时,你都会对表中的每一行使用那个大的球余弦定律公式。这是full table scan。很可能您的大部分缓慢都来自表扫描,因为现代计算机一旦将数据放入 RAM 中就会非常快速地进行数学运算。
但是,你很幸运。您的搜索会查找候选点 200 英里半径范围内的点。这意味着您可以使用WHERE ... BETWEEN
子句来消除距起点以南或以北(纬度)超过 200 英里的点。
为此,您需要知道每个纬度有 69.0 法定英里、60 海里和 111.045 公里。因此,您应该搜索点 ± (200/69) 所以....尝试这样的查询。
SELECT *, (
6371 * acos (
cos ( radians(33.577718) )
* cos( radians( `Latitude` ) )
* cos( radians( `Longitude` ) - radians(115.846524) )
+ sin ( radians(33.577718) )
* sin( radians( `Latitude` ) )
)
) AS `distance`
FROM `geopc_cn_places_grouped`
WHERE `Latitude`!=33.577718 AND `Longitude`!=115.846524
AND Latitude BETWEEN 33.577718 - (200/69) AND 33.577718 + (200/69)
HAVING `distance` < 200
ORDER BY `distance` ASC
LIMIT 30;
然后在您的 Latitude
列上创建一个索引。
CREATE INDEX latsearch ON geopc_cn_places_grouped(Latitude);
我建议的Latitude BETWEEN
子句然后会执行index range scan 并因此跳过表中的许多行。这是加快查询速度的经典 SQL 方式。
这是对这个问题的理想答案的简化。 I wrote up this problem here.
【讨论】:
你是个天才!现在执行时间减半了,我对结果完全满意,太棒了,谢谢!【参考方案2】:您的查询必须计算每一行的距离。快速的解决方案是使用“边界框”。这将要测试的行数限制为纬度条或经度条。
详细信息(以及更高级的加速):http://mysql.rjweb.org/doc.php/find_nearest_in_mysql
【讨论】:
以上是关于如何优化复杂计算查询的执行时间?的主要内容,如果未能解决你的问题,请参考以下文章
如何优化执行嵌套在 group-by 子句中的计数的 SQL 查询?