mysql - 如何使用经度和纬度搜索最近的用户,同时在 MySQL 中以有效的方式按性别和年龄进行过滤?
问题描述
我习惯了 BTREE 索引,我知道如何应用多列索引来优化普通查询。
我有一个这样的示例数据库:
DROP DATABASE IF EXISTS `gis`;
CREATE DATABASE IF NOT EXISTS `gis`
DEFAULT CHARACTER SET utf8
DEFAULT COLLATE utf8_general_ci;
USE `gis`;
DROP TABLE IF EXISTS user;
CREATE TABLE IF NOT EXISTS user (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
firstname VARCHAR(48) NOT NULL,
sex ENUM('male', 'female') NOT NULL,
age TINYINT UNSIGNED NOT NULL,
position POINT NOT NULL
);
ALTER TABLE user ADD INDEX sex__age (sex, age);
ALTER TABLE user ADD SPATIAL INDEX(position);
INSERT INTO user (firstname, sex, age, position) VALUES ('Alexander', 'male', 34, POINT(63.429909, 10.393035));
INSERT INTO user (firstname, sex, age, position) VALUES ('Dina', 'female', 21, POINT(63.426300, 10.392481));
INSERT INTO user (firstname, sex, age, position) VALUES ('Martin', 'male', 32, POINT(63.422304, 10.432027));
INSERT INTO user (firstname, sex, age, position) VALUES ('Tina', 'female', 19, POINT(63.430603, 10.373038));
INSERT INTO user (firstname, sex, age, position) VALUES ('Kristin', 'female', 20, POINT(63.434858, 10.411359));
INSERT INTO user (firstname, sex, age, position) VALUES ('Mette', 'female', 33, POINT(63.420422, 10.403811));
INSERT INTO user (firstname, sex, age, position) VALUES ('Andres', 'male', 34, POINT(63.419488, 10.395722));
INSERT INTO user (firstname, sex, age, position) VALUES ('Sandra', 'female', 25, POINT(63.432053, 10.408738));
INSERT INTO user (firstname, sex, age, position) VALUES ('Kine', 'female', 29, POINT(63.432302, 10.412643));
INSERT INTO user (firstname, sex, age, position) VALUES ('Henrik', 'male', 25, POINT(63.421055, 10.443288));
如果我按性别和年龄进行正常查询和查询,它会使用正确的索引,并且只在该查询中查找 2 行,这是它应该做的,它向我显示查询和索引工作正常。
EXPLAIN SELECT id, firstname, sex, age FROM user WHERE sex = 'male' AND age BETWEEN 25 AND 32;
它使用 key: sex__age
index 并根据年龄进行范围搜索,检查的行数仅为 2,这很好。
但后来我尝试按位置进行查找,并检查 3.5 公里内的用户,但它检查所有行并且不使用空间索引。
SET @distance = 3.5;
SET @my_place_lng = 63.431592;
SET @my_place_lat = 10.396210;
SELECT
id,
firstname,
sex,
age,
ST_Distance_Sphere(Point(@my_place_lng, @my_place_lat), position) AS distance_from_me
FROM user
WHERE
ST_Contains(ST_MakeEnvelope(
Point((@my_place_lng+(@distance/111)), (@my_place_lat+(@distance/111))),
Point((@my_place_lng-(@distance/111)), (@my_place_lat-(@distance/111)))
), position)
ORDER BY distance_from_me ASC;
我怎样才能做到这一点并让 MySQL 使用空间索引?
而且我已经知道我不能组合 RTREE 和 BTREE 索引,所以空间和普通索引不能组合。关于如何优化这样的东西有什么建议吗?
解决方案
创建空间索引时是否收到任何警告?MySQL 对 SRID 要求有奇怪的行为,如此处所述
https://mysqlserverteam.com/geographic-indexes-in-innodb/
尝试设置 SRID。
推荐阅读
- google-maps - Google Maps API:有没有办法在 2 个地方之间的路线上查找分段信息
- android - ImageButton 使用@android:drawable/ 以编程方式设置drawable
- terraform - 需要为 terraform 中的用例提供建议的完整流程
- java - 链接和排序数组
- r - 使用 purrr 的逐行迭代无法按预期工作
- java - Spring WebFlux Reactor - 在 Flux 中更新对象
- javascript - 敌人自动向玩家旋转
- python - 为什么我的函数计算两点之间的距离错误
- r - R试图在数据集的多个子集上运行dfsummary和freqs作为宏
- r - 最大化主动回报 最小化主动风险 投资组合分析 R