Sql 选择最近点的最有效方法
我有两个结构相同的非常大的表,包含两种类型的位置: 失水事故 Id-INT 浮动纬度 Y-浮动经度 及 LocB Id-INT 浮动纬度 Y-浮动经度 他们每个人都有几百万排。我需要选择LocA中的所有位置,并为每个位置选择LocB中最近的位置 要做到这一点,最有效的查询是什么 EDIT1:距离算法将是一个愚蠢的算法:SQRTPOWERLocB.X-LocA.X,2+POWERLocB.Y-LocA.Y,2 EDIT2:我已经完成了一个实现,但我真的不确定它是否是最优的,我高度怀疑它,它将是:Sql 选择最近点的最有效方法,sql,sql-server,performance,tsql,geospatial,Sql,Sql Server,Performance,Tsql,Geospatial,我有两个结构相同的非常大的表,包含两种类型的位置: 失水事故 Id-INT 浮动纬度 Y-浮动经度 及 LocB Id-INT 浮动纬度 Y-浮动经度 他们每个人都有几百万排。我需要选择LocA中的所有位置,并为每个位置选择LocB中最近的位置 要做到这一点,最有效的查询是什么 EDIT1:距离算法将是一个愚蠢的算法:SQRTPOWERLocB.X-LocA.X,2+POWERLocB.Y-LocA.Y,2 EDIT2:我已经完成了一个实现,但我真的不确定它是否是最优的,我高度怀疑它,它将是:
SELECT A.Id AS AId,
( SELECT TOP 1 B.Id
FROM B
ORDER BY SQRT(POWER(B.X - A.X, 2) + POWER(B.Y - A.Y, 2)) ASC
) AS BId
FROM A
EDIT3:表LocB中存在重复项是很常见的,但我希望为LocA中的某个位置返回任何最接近的匹配项,而不是全部。以下是代码:
WITH S AS (
SELECT *
FROM LOCA CROSS APPLY( select locb.id as ID_B, (POWER(LocB.X - LocA.X, 2) + POWER(LocB.Y - LocA.Y, 2)) D FROM LOCB ) S
)
SELECT DISTINCT ID,X,Y,d,ID_B
FROM S
where d=(select min(d) from s s1 where s1.ID=s.id)
这可能不是很有效率,但目前我看不到更好的方法:
SELECT a.ID, a.X, a.Y, b.ID, b.X, b.Y, b.Distance
FROM LocA a
CROSS APPLY
( SELECT TOP 1 WITH TIES
b.ID,
b.X,
b.Y,
Distance = SQRT(POWER(b.X - a.X, 2) + POWER(b.Y - a.Y, 2))
FROM LocB b
ORDER BY Distance
) B;
那么:
SELECT id as Aid,x,y,m % 100 as bId
FROM (
SELECT A.id,A.x,A.y,MIN(CAST(((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)) AS BIGINT)*100+B.id) as m
FROM A
CROSS JOIN B
GROUP BY A.id,A.x,A.y) j;
SQRT不会改变顺序-它只是开销
SELECT A.Id AS AId,
( SELECT TOP 1 B.Id
FROM B
ORDER BY POWER(B.X - A.X, 2) + POWER(B.Y - A.Y, 2) ASC
) AS BId
FROM A
我认为有一种方法可以完成两次传球
你知道距离是你有没有想过要考虑,方法,并在这些点列上创建一个
如果您的数据库结构是固定的,您可以添加一个新的持久化计算列。使用什么算法进行最接近?有many@Jamiec当前位置不要太早。我们仍在讨论10000000²的计算。您将如何处理等距点?返回所有匹配点?就一个?另外,这是一次性查询还是重复查询?我建议您检查一下此类查询。您最感兴趣的是这一特定页面:回答很好,但我认为OP想要的是最近的位置lat/long,而不是最小距离。是的,的确如此。我还需要LocB中位置的ID。不过,感谢您花时间构建它!为什么在从S选择不同ID,X,Y,MIND OVERPARTITION BY ID FROM S中使用窗口函数,而不是更传统的选择ID,X,Y,MIND FROM S GROUP BY ID,X,Y;?假设ID是主键,则两者是同义词,后者效率更高,在我看来更具可读性。这有一个问题,如果两个点的距离相同,则返回其中一个。@Amirezakeshavarz更正以解决关系问题,如果有联系,它将返回所有记录。这与OP的查询几乎相同-只是它提供了要添加的“带联系”选项。@Ypercurbe是的,在我开始回答时,编辑还没有完成,并且由于我页面上答案框的位置,我看不到指示问题已编辑的标志,因此,当我看到OP所写的内容时,我已经发布了答案。它还有一个额外的好处,即允许在单个查询中返回距离和ID,如果不是这样,我会删除它。这不会返回重复的距离。
create #temp1
IDa
IDb
Xa
Ya
Xb
Yb
distSum
distAct
insert into #temp (IDa, IDb, Xa, Ya, Xb ,Yb, distSum)
select a.ID, b.ID, a.x, a.y, b.x, b.y, abs(a.X-b.X) + abs(a.Y-b.Y)
table as a
join table as b
on a.ID < b.ID
delete #temp
from #temp
join
(select IDa, min(distSum) as minDistSum from #temp group by IDa) as aMin
on #temp.IDa = aMin.IDa
and #temp.distSum > 1.414*(minDistSum)
update #temp
set distAct = POWER(Xa - Xb, 2) + POWER(Ya - Yb, 2)