在JOIN之后添加简单的AND会导致性能下降

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.

Mik*_*e M 2

这是一个有趣的问题。

通过从“<>”更改为“">”,您可以获得巨大的性能提升,这并非不现实。

正如其他人提到的,诀窍是充分利用索引。当然,通过使用“>”,您应该可以轻松地让服务器将您的 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)