另一个为什么这个最近邻居空间查询如此缓慢?

时间:2015-08-22 14:56:28

标签: sql sql-server tsql nearest-neighbor spatial-index

this recommendation之后进行优化的最近邻居更新,我使用下面的tsql来更新每个点最近的兴趣点11,000点的GPS表。

WHILE (2 > 1) 
  BEGIN 
    BEGIN TRANSACTION 
    UPDATE TOP ( 100 ) s 
set 
[NEAR_SHELTER]= fname,
[DIST_SHELTER] = Shape.STDistance(fshape)
from(
Select
[dbo].[GRSM_GPS_COLLAR].*,
fnc.NAME as fname,
fnc.Shape as fShape
from
[dbo].[GRSM_GPS_COLLAR]
CROSS APPLY (SELECT TOP 1 NAME, shape                   
FROM [dbo].[BACK_COUNTRY_SHELTERS] WITH(index ([S50_idx]))                
WHERE [BACK_COUNTRY_SHELTERS].Shape.STDistance([dbo].[GRSM_GPS_COLLAR].Shape) IS NOT NULL
                  ORDER BY BACK_COUNTRY_SHELTERS.Shape.STDistance([dbo].[GRSM_GPS_COLLAR].Shape) ASC) fnc)s; 

    IF @@ROWCOUNT = 0 
      BEGIN 
        COMMIT TRANSACTION 
         BREAK 
      END 
    COMMIT TRANSACTION 
    -- 1 second delay
    WAITFOR DELAY '00:00:01'
  END -- WHILE
GO

请注意,我是以100块为单位进行操作以避免锁定,如果我不进行锁定,我会得到它,并且在我必须杀死之前它会运行几个小时。显而易见的答案是"你有没有优化你的空间索引"答案是肯定的,两个表都有一个空间索引(SQL 2012),Geography Autogrid,每个对象4092个单元格,经过多天测试索引参数的每个可能的排列后,它被发现是最有效的索引。我已经尝试了这个有和没有空间索引提示....有多个空间索引。

enter image description here

在上面,请注意空间索引搜索成本和没有列统计信息的警告,我理解空间索引的情况。在每种情况下,我最终都必须终止tsql。它只是永远运行(在一种情况下一夜之间,更新了2300行)。

我已尝试Isaac's numbers table join solution,但该示例似乎不适合循环进行n次距离搜索,只需一个用户提供的位置(@x)。

更新

@ Brad D基于你的答案,我试过这个,有一些语法错误,我无法弄清楚......我不确定我是否正确地将你的例子转换为我的。我有什么想法,我做错了什么?谢谢!

;WITH Points as(
SELECT TOP 100 [NAME], [Shape] as GeoPoint
FROM [BACK_COUNTRY_SHELTERS]
WHERE 1=1 


SELECT P1.*, CP.[GPS_POS_NUMBER] as DestinationName, CP.Dist
INTO #tmp_Distance
FROM [GRSM_GPS_COLLAR] P1
CROSS APPLY (SELECT [NAME] ,    Shape.STDistance(P1.GeoPoint)/1609.344 as     Dist
FROM [BACK_COUNTRY_SHELTERS] as P2
WHERE 1=1 
AND P1.[NAME] <> P2.[NAME] --Don't compare it to itself

) as CP

CREATE CLUSTERED INDEX tmpIX ON #tmp_Distance (name, Dist)


SELECT * FROM
(SELECT *, ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Dist ASC) as Rnk FROM #tmp_Distance) as tbl1
WHERE rnk = 1
DROP TABLE #tmp_Distance

2 个答案:

答案 0 :(得分:1)

你实际上是在比较1.21亿个数据点(11K起点到11K目的地),这不能很好地扩展,试图一下子完成这一切。我喜欢你把它分成批量的想法,但试图对没有索引的1.1MM记录的结果集进行排序可能会很痛苦。

我建议将其分解为更多操作。我刚尝试了以下内容,它在我的环境中每批运行不到一分钟。 (5500位置记录)

这可以为我工作,没有地理空间索引,但是在原点和到目的地的距离周围有一个clusted索引。

%A.very.long.and.deeply.nested.hash.value

对100条记录,甚至11000条记录的实际更新不应该花费太长时间。空间索引是很酷的,但是我错过了一些我没有看到这个特定练习的严格要求。

答案 1 :(得分:0)

你应该重新设计这个过程。不只是调整索引。 使用所需的列创建表的副本。如果您使用更大的表,您可以批量工作。 然后对于边桌,为每个“最近”点设置。 然后运行一个循环,使用聚集索引进行连接,以5k以下的批量更新主表(这样不会导致表锁升级)。这通常比在活动表上运行大规模更新更快,更安全。 在辅助表上,为循环添加“已处理”列以更新主表。以及主表的已处理列和聚簇索引列上的索引,以防止在加入主表时无法进行“排序”。