【问题标题】:Another Why Is This Nearest Neighbor Spatial Query So Slow?另一个为什么这个最近邻空间查询这么慢?
【发布时间】:2015-11-16 09:54:28
【问题描述】:

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 个单元格,经过多天的研究,发现这是最有效的索引测试索引参数的所有可能排列。我已经尝试过使用和不使用空间索引提示......使用多个空间索引。

在上面,请注意空间索引查找成本和关于无列统计信息的警告,据我所知,空间索引就是这种情况。在每种情况下,我最终都必须终止 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

【问题讨论】:

  • 您还应该发布查询explain。您为单个点查找邻居的查询时间是多少?我使用类似于 Isaac 样本的东西。我创建了一个函数,然后使用该函数进行更新。
  • tsql 查询从 op 中的第 3 行开始。单点搜索...小于 0.01 秒。当它搜索 n 行中的每一行的最近邻居时,它就会锁定。
  • 那么搜索邻居不是问题。创建您的function(gps_id) return id。只需执行update set neighbordid = function(gps_id)。我希望我能提供更多帮助,但我更多的是 postgresql postgis 类型。
  • 将一个行 ID 和你最近的邻居写入另一个表是一个想法吗?这里几点了?你可以把这个写回去……在一个同时大量更新的表中进行繁重的计算总是很困难的……

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


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    您实际上是在比较 1.21 亿个数据点(11K 起点到 11K 目的地),如果想一口气完成所有这些,这将无法很好地扩展。我喜欢你将它分成批次的想法,但是尝试对没有索引的 1.1MM 记录的结果集进行排序可能会很痛苦。

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

    这对我有用,不需要地理空间索引,而是围绕起点和到目的地的距离的聚集索引。

    ;WITH Points as(
    SELECT TOP 100 Name, AddressLine1,
        AddressLatitude, AddressLongitude
        , geography::STGeomFromText('POINT(' + CONVERT(varchar(50),AddressLatitude) + ' ' + CONVERT(varchar(50),AddressLongitude)     + ')',4326) as GeoPoint
    FROM ServiceFacility
    WHERE 1=1 
    AND AddressLatitude BETWEEN -90 AND 90
    AND AddressLongitude BETWEEN -90 AND 90)
    
    SELECT P1.*, CP.Name as DestinationName, CP.Dist
    INTO #tmp_Distance
    FROM Points P1
    CROSS APPLY (SELECT Name, AlternateName,
        geography::STGeomFromText('POINT(' + CONVERT(varchar(50),P2.AddressLatitude) + ' ' + CONVERT(varchar(50),P2.AddressLongitude) + ')',4326).STDistance(P1.GeoPoint)/1609.344 as     Dist
    FROM ServiceFacility as P2
    WHERE 1=1 
    AND P1.Name <> P2.Name --Don't compare it to itself
    AND P2.AddressLatitude BETWEEN -90 AND 90
    AND P2.AddressLongitude BETWEEN -90 AND 90
    ) 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
    

    100 条记录,甚至 11000 条记录的实际更新时间不会太长。空间索引很酷,但如果我遗漏了一些东西,我认为对于这个特定的练习没有硬停止要求。

    【讨论】:

      猜你喜欢
      • 2011-03-11
      • 2020-03-19
      • 2014-03-12
      • 2011-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-16
      • 1970-01-01
      相关资源
      最近更新 更多