Mysql Select 地理空间计数 ST_Contains 对于多行非常慢
Mysql Select count with geospatial ST_Contains is very slow with multiple rows
我有一个 mysql 查询来获取一个区域的所有地点。如果我只查询一个id,那真的很快,如果我查询两个或更多id,那真的很慢。
Areas.geometry 和 Places.location 是 SPATIAL 索引。
区域table只有3行(都有复杂的几何形状。第3行更复杂),商店有3000行。如果你想测试,我建立了一个演示 sql 文件来导入:geospatial-exemple.sql
一些例子:
此查询 运行ning 在 260 毫秒内:
select a.name,
(
SELECT count(*)
FROM places p
WHERE ST_Contains(a.geometry,p.location)
) as places_count
FROM areas a
WHERE a.id in (1)
此查询 运行ning 在 320 毫秒内:
select a.name,
(
SELECT count(*)
FROM places p
WHERE ST_Contains(a.geometry,p.location)
) as places_count
FROM areas a
WHERE a.id in (3)
此查询 运行宁 50 秒 :
select a.name,
(
SELECT count(*)
FROM places p
WHERE ST_Contains(a.geometry,p.location)
) as places_count
FROM areas a
WHERE a.id in (1,3)
我还尝试使用更复杂的 MULTIPOLYGON
对查询中的 areas.geometry 进行硬编码
此查询 运行ning 在 380 毫秒内:
select a.name,
(
SELECT count(*)
FROM places p
WHERE ST_Contains(ST_GeomFromText("MULTIPOLYGON((...))",
4326,
'axis-order=long-lat'),p.location)
) as places_count
FROM areas a
WHERE a.id in (1,3)
很明显,运行 多个查询比只查询一个并等待一分钟要快。如果有人知道这是一个 mysql 错误还是有其他方法可以做到这一点?
使用 Join 查询会得到相同的结果。
我会尝试将其表示为连接,看看 MySQL 运行 是否更快。不确定 MySQL 是否优化了空间连接,但在我使用的数据库中它会更快。
类似这样的东西(我没有检查语法):
SELECT areas.name, count(*) as places_count
FROM places p JOIN areas a
ON ST_Contains(a.geometry, p.location)
WHERE a.type = "city"
GROUP BY 1;
根据John Powells answer here,空间索引有一个未记录的限制:
For the Contains and Intersects functions to work properly, and for the index to be used, you need to have one of the geometries be a constant. This doesn't appear to be documented, although all the examples you will see with MySQL with Intersects/Contains work this way.
所以 运行 每个区域一个区域的多个查询确实会更快。
如果您有创建函数的权限,您可以通过 运行 函数中的子查询使用变通方法,其中 areas.geometry
现在将作为 [=13= 的常量参数]:
CREATE FUNCTION fn_getplacescount(_targetarea GEOMETRY)
RETURNS INT READS SQL DATA
RETURN (SELECT COUNT(*) FROM places p WHERE ST_Contains(_targetarea, p.location));
现在
SELECT a.name, fn_getplacescount(a.geometry) AS places_count
FROM areas a WHERE a.id in (1,3);
类似于 运行 每个区域,并且执行时间应该与使用两个单独的查询相似。
我有一个 mysql 查询来获取一个区域的所有地点。如果我只查询一个id,那真的很快,如果我查询两个或更多id,那真的很慢。
Areas.geometry 和 Places.location 是 SPATIAL 索引。
区域table只有3行(都有复杂的几何形状。第3行更复杂),商店有3000行。如果你想测试,我建立了一个演示 sql 文件来导入:geospatial-exemple.sql
一些例子:
此查询 运行ning 在 260 毫秒内:
select a.name,
(
SELECT count(*)
FROM places p
WHERE ST_Contains(a.geometry,p.location)
) as places_count
FROM areas a
WHERE a.id in (1)
此查询 运行ning 在 320 毫秒内:
select a.name,
(
SELECT count(*)
FROM places p
WHERE ST_Contains(a.geometry,p.location)
) as places_count
FROM areas a
WHERE a.id in (3)
此查询 运行宁 50 秒 :
select a.name,
(
SELECT count(*)
FROM places p
WHERE ST_Contains(a.geometry,p.location)
) as places_count
FROM areas a
WHERE a.id in (1,3)
我还尝试使用更复杂的 MULTIPOLYGON
对查询中的 areas.geometry 进行硬编码此查询 运行ning 在 380 毫秒内:
select a.name,
(
SELECT count(*)
FROM places p
WHERE ST_Contains(ST_GeomFromText("MULTIPOLYGON((...))",
4326,
'axis-order=long-lat'),p.location)
) as places_count
FROM areas a
WHERE a.id in (1,3)
很明显,运行 多个查询比只查询一个并等待一分钟要快。如果有人知道这是一个 mysql 错误还是有其他方法可以做到这一点? 使用 Join 查询会得到相同的结果。
我会尝试将其表示为连接,看看 MySQL 运行 是否更快。不确定 MySQL 是否优化了空间连接,但在我使用的数据库中它会更快。
类似这样的东西(我没有检查语法):
SELECT areas.name, count(*) as places_count
FROM places p JOIN areas a
ON ST_Contains(a.geometry, p.location)
WHERE a.type = "city"
GROUP BY 1;
根据John Powells answer here,空间索引有一个未记录的限制:
For the Contains and Intersects functions to work properly, and for the index to be used, you need to have one of the geometries be a constant. This doesn't appear to be documented, although all the examples you will see with MySQL with Intersects/Contains work this way.
所以 运行 每个区域一个区域的多个查询确实会更快。
如果您有创建函数的权限,您可以通过 运行 函数中的子查询使用变通方法,其中 areas.geometry
现在将作为 [=13= 的常量参数]:
CREATE FUNCTION fn_getplacescount(_targetarea GEOMETRY)
RETURNS INT READS SQL DATA
RETURN (SELECT COUNT(*) FROM places p WHERE ST_Contains(_targetarea, p.location));
现在
SELECT a.name, fn_getplacescount(a.geometry) AS places_count
FROM areas a WHERE a.id in (1,3);
类似于 运行 每个区域,并且执行时间应该与使用两个单独的查询相似。