gpt4 book ai didi

mysql - 与 MyISAM 相比,innodb 的距离搜索非常慢

转载 作者:行者123 更新时间:2023-11-29 20:41:36 25 4
gpt4 key购买 nike

我有一个简单的 SELECT mysql 请求,用于按距离对用户进行排序,如下所示:

SELECT 
( 6371 * acos( cos( radians(48.85980226) ) * cos( radians( latitude ) ) * cos( radians
( longitude ) - radians(2.29202271) ) + sin( radians(48.85980226) ) * sin( radians( latitude
) ) ) ) AS distance,
id FROM `users`
HAVING distance <= '100'
ORDER BY distance ASC

我的数据库 (MySql 5.7) 中有大约 50.000 个用户。当我将表设置为MyISAM时,请求速度还算合理,大约0.2秒;但如果我把引擎转为innodb,大约需要8s!我确实需要使用 innodb,因为数据经常被写入和读取(MyISAM 导致很多“myisam 等待表级锁”)。知道如何优化该查询的速度吗?谢谢!

(对不起我的英语)

EDIT2:我将坐标类型从 DECIMAL 更改为 FLOAT,并且查询速度更快一点:5 秒而不是 8 秒...

Edit3(来自评论,带有边界框)

SELECT  ( 6371 * acos( cos( radians(48.85980226) ) *
cos( radians( latitude ) ) * cos( radians ( longitude ) -
radians(2.29202271) ) + sin( radians(48.85980226) ) *
sin( radians( latitude ) ) ) ) AS distance,
uid
FROM users
WHERE longitude between 0.089154409442052 AND 4.4948910105579
AND latitude between 47.410526897681 AND 50.309077622319
HAVING distance <= '100'
ORDER BY distance ASC

编辑 4:这是我的表结构:

CREATE TABLE `users` 
( `id` mediumint(9) NOT NULL AUTO_INCREMENT,
`uid` varchar(20) NOT NULL,
`token` varchar(70) NOT NULL,
`last_connection` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`email` varchar(255) NOT NULL,
`longitude` float NOT NULL,
`latitude` float NOT NULL,
`presentation` text NOT NULL,
PRIMARY KEY (`id`),
KEY `uid` (`uid`),
KEY `uid_token` (`uid`,`token`),
KEY `longitude` (`longitude`),
KEY `latitude` (`latitude`)
) ENGINE=InnoDB AUTO_INCREMENT=53004 DEFAULT CHARSET=utf8

字段last_connection更新非常频繁。在线用户越多,查询速度就越慢...我猜由于更新,行被临时锁定并且查询速度变慢...:/使用MyISAM时,搜索查询还可以,但是更新速度很慢(等待锁)

编辑 5这是我的更新查询:

UPDATE `users` SET `last_connection` = CURRENT_TIMESTAMP WHERE `uid` = 'XXXX';  

我改变了它并添加了限制1:

UPDATE `users` SET `last_connection` = CURRENT_TIMESTAMP WHERE `uid` = 'XXXX' LIMIT 1;  

这似乎更快。我需要等待更多用户连接来检查差异是否很大

最佳答案

数据库引擎对每一行进行计算。

那么将已经计算出的值存储为变量怎么样?

SET @cos_point1 = cos(radians(48.85980226));

SET @rad_point1 = radians(2.29202271);

SET @sin_point1 = sin(radians(48.85980226));

SELECT
( 6371 * acos( @cos_point1 * cos( radians( latitude ) ) * cos( radians
( longitude ) - @rad_point1 ) + @sin_point1 * sin( radians( latitude
) ) ) ) AS distance,
id FROM `users`
HAVING distance <= 100
ORDER BY distance ASC;



我还有一个想法!

试试这个:

1)创建Memory类型的表users_geodata(因为真正的数据将在users表中,所以我们对临时表使用最快的引擎):

CREATE TABLE `users_geodata` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`latitude` float NOT NULL,
`longitude` float NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=Memory;

2) 安排执行此操作的同步:

REPLACE INTO users_geodata 
SELECT id, latitude, longitude FROM users

3) 运行您的查询:

SELECT 
( 6371 * acos( cos( radians(48.85980226) ) * cos( radians( latitude ) ) * cos( radians
( longitude ) - radians(2.29202271) ) + sin( radians(48.85980226) ) * sin( radians( latitude
) ) ) ) AS distance,
id FROM `users_geodata`
HAVING distance <= 100
ORDER BY distance ASC

关于mysql - 与 MyISAM 相比,innodb 的距离搜索非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38619856/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com