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

标签 mysql query-optimization innodb distance myisam

我有一个简单的 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/

相关文章:

mysql - 如何仅选择唯一记录

php - mysql查询获取2个日期之间的第一个特定日期

mysql - 如何发现MariaDB崩溃的原因?

innodb - 恢复后mysqldump数据丢失

mysql - 处理searchresults.jsp时出现异常

php - 数据库插入时IP地址错误

mysql union,不同的查询优化

sql - 使用 ROW_NUMBER() 随机获取记录的问题 (SQL Server 2005)

mysql - 如何优化此 sql 查询(内连接)

mysql - 为什么 MySQL 的 MyISAM 引擎不支持外键?