sql-server - 在 Radius 中查找 GeographyPoints 的最佳方法
问题描述
我在 SQL Server 2019 标准上有一个包含数百万个位置的表和一个包含大约 10 万个兴趣点的表。现在我正在尝试将以下逻辑投射到查询中:“向我显示所有在半径 500m 到 2000m 范围内有公交车站的位置”(将来我想指定给定范围内的公交车站的确切数量半径)
我最初的方法是这样的:
SELECT
L.ID,
COUNT(*)
FROM
dbo.Locations AS L
INNER JOIN POI AS P ON P.GeographyPoint.STDistance(L.GeographyPoint) BETWEEN 500 AND 2000
这基本上是可行的,但执行时间对于 Web 应用程序来说是不可接受的,并且会随着距离和 POI 数量的增加而增加。我也试过加入
P.GeographyPoint.STBuffer(500).STContains(L.GeographyPoint) = 0 AND
P.GeographyPoint.STBuffer(2000).STContains(L.GeographyPoint) = 1
或Filter(L.GeographyPoint) = 1
或STIntersects(L.GeographyPoint) = 1
略有不同但仍不令人满意的结果。我还尝试在预先计算的缓冲地理列上为 1000m 半径创建空间索引,这需要一个小时并创建了一个性能仍然很差的巨大索引空间。缓存所有 POI 到所有位置的所有距离将导致大约 4000 亿行,所以这也是没有选择的。
任何帮助表示赞赏!
解决方案
我认为您预先计算您所在位置周围区域的本能是一种很好的本能。但正如另一位评论者所说,空间查询优化假设了一些事情,而你的“这个和那个之间的距离”不符合这些假设。
然而!我想我想出了“一个奇怪的技巧”来让你得到你想要的东西。请注意以下事项:
declare @p geography = geography::Point(37.540830, -122.299880, 4236);
select @p.STBuffer(2000).STIntersection(@p.STBuffer(500).ReorientObject());
这将创建一个外半径为 2000m、内半径为 500m 的甜甜圈,以指定点为中心。如果您将其存储在预先计算的列中,您应该能够执行以下操作:
SELECT
L.ID,
COUNT(*)
FROM
dbo.Locations AS L
INNER JOIN POI AS P ON P.GeographyPoint.STIntersects(L.Donut) = 1;
为了使这种尝试变得便宜,您可以将这些甜甜圈放入一个单独的表中,该表只是(LocationID,Donut)。这样,您可以计算这些点,例如,您的 100 个点,并尝试无需更改实际位置表的空间查询。如果您走这条路线,您可以更改查询以针对此新表而不是针对位置。
推荐阅读
- ios - 从 Pushwoosh 切换后 OneSignal 订阅者未更新
- api - salesforcerest.update 在 WSO2 EI 6.1.1 中不起作用
- c++ - C++ 这个函数调用之前的 (void) 有什么作用?
- python - Converting PDF document to DataFrame
- html - 如何避免 td 中的文本重叠?
- c# - C# Winform 刷新图像导致延迟
- react-native - 在 generateIDs 处未捕获错误:keyPath 无效
- php - 将 Pregmatch 值存储在变量中
- c# - 如何在 ASP.Net Core Razor 页面中返回带有模型的页面
- flutter - dart assert 声明的一个很好的解释