Lan*_*yor 6 sql sql-server geospatial spatial-query
我有一个包含大约500个点的表,我正在寻找容差范围内的重复项.这需要不到一秒钟,给我500行.大多数的距离为零,因为它给出了相同的点(PointA = PointB)
DECLARE @TOL AS REAL
SET @TOL = 0.05
SELECT
PointA.ObjectId as ObjectIDa,
PointA.Name as PTNameA,
PointA.[Description] as PTdescA,
PointB.ObjectId as ObjectIDb,
PointB.Name as PTNameB,
PointB.[Description] as PTdescB,
ROUND(PointA.Geometry.STDistance(PointB.Geometry),3) DIST
FROM CadData.Survey.SurveyPoint PointA
JOIN [CadData].Survey.SurveyPoint PointB
ON PointA.Geometry.STDistance(PointB.Geometry) < @TOL
-- AND
-- PointA.ObjectId <> PointB.ObjectID
ORDER BY ObjectIDa
Run Code Online (Sandbox Code Playgroud)
如果我使用靠近底部的注释掉的行,我会得到14行,但执行时间最长可达14秒.在我的积分表扩大到数十万之前,这笔交易并不是那么大.
如果答案已经存在,我会提前道歉.我确实看了,但是新的我迷失了阅读的帖子,这些都是我的头脑.
ADDENDUM:ObjectID是一个bigint和表的PK,所以我意识到我可以将语句更改为
AND PointA.ObjectID > PointB.ObjectID
Run Code Online (Sandbox Code Playgroud)
现在这需要一半的时间,并给我一半的结果(7秒内7行).我现在不会重复(因为在第4点接近第8点,然后第8点接近第4点).然而,性能仍然令我担忧,因为该表将非常大,因此任何性能问题都将成为问题.
附录2:如下所示更改JOIN和AND(或建议的WHERE)的顺序也没有区别.
DECLARE @TOL AS REAL
SET @TOL = 0.05
SELECT
PointA.ObjectId as ObjectIDa,
PointA.Name as PTNameA,
PointA.[Description] as PTdescA,
PointB.ObjectId as ObjectIDb,
PointB.Name as PTNameB,
PointB.[Description] as PTdescB,
ROUND(PointA.Geometry.STDistance(PointB.Geometry),3) DIST
FROM CadData.Survey.SurveyPoint PointA
JOIN [CadData].Survey.SurveyPoint PointB
ON PointA.ObjectId < PointB.ObjectID
WHERE
PointA.Geometry.STDistance(PointB.Geometry) < @TOL
ORDER BY ObjectIDa
Run Code Online (Sandbox Code Playgroud)
我觉得很有意思的是,我可以将@Tol值更改为大的,返回超过100行而性能没有变化,即使它需要很多计算.但随后添加一个简单的A.
这是一个有趣的问题。
通过从“<>”更改为“">”,您可以获得巨大的性能提升,这并非不现实。
正如其他人提到的,诀窍是充分利用索引。当然,通过使用“>”,您应该可以轻松地让服务器将您的 PK 限制在该特定范围内 - 当您已经检查过“向前”查看时,避免“向后”查看。
此改进将扩展 - 将在您添加行时有所帮助。但你担心这无助于阻止工作量的增加,这是正确的。正如您所想的那样,只要您必须扫描更多的行,就会花费更长的时间。这就是这里的情况,因为我们总是想比较一切。
如果第一部分看起来不错,只是 TOL 检查,您是否考虑过完全拆分第二部分?
将第一部分更改为转储到临时表中
SELECT
PointA.ObjectId as ObjectIDa,
PointA.Name as PTNameA,
PointA.[Description] as PTdescA,
PointB.ObjectId as ObjectIDb,
PointB.Name as PTNameB,
PointB.[Description] as PTdescB,
ROUND(PointA.Geometry.STDistance(PointB.Geometry),3) DIST
into #AllDuplicatesWithRepeats
FROM CadData.Survey.SurveyPoint PointA
JOIN [CadData].Survey.SurveyPoint PointB
ON
PointA.Geometry.STDistance(PointB.Geometry) < @TOL
ORDER BY ObjectIDa
Run Code Online (Sandbox Code Playgroud)
您可以在下面编写跳过重复项的直接查询。它并不特别,但相对于临时表中的小集合,它应该非常快。
Select
*
from
#AllDuplicatesWithRepeats d1
left join #AllDuplicatesWithRepeats d2 on (
d1.objectIDa = d2.objectIDb
and
d1.objectIDb = d2.objectIDa
)
where
d2.objectIDb is null
Run Code Online (Sandbox Code Playgroud)