SQL Cross应用性能问题

时间:2012-01-31 21:51:29

标签: sql distance apply

我的数据库有一个分布在美国各地的大约2,000个地点的目录,包含邮政编码信息(我已将其与lon / lat坐标联系起来)。

我还有一个表函数,它接受两个参数(ZipCode和Miles)来返回相邻邮政编码列表(不包括搜索到的相同邮政编码)

对于我想要获取相邻位置ID的每个位置。因此,如果位置#4有三个附近位置,则输出应如下所示:

  1. 4 5
  2. 4 24
  3. 4 137
  4. 即,位置5,24和137位于位置4的X英里内。

    我最初尝试使用我的函数交叉应用,如下所示:

    SELECT A.SL_STORENUM,A.Sl_Zip,Q.SL_STORENUM FROM tbl_store_locations AS A
    CROSS APPLY (SELECT SL_StoreNum FROM tbl_store_locations WHERE SL_Zip in (select zipnum from udf_GetLongLatDist(A.Sl_Zip,7))) AS Q 
    WHERE A.SL_StoreNum='04'
    

    然而,在没有结果的情况下跑了20多分钟,所以我取消了它。我在zipcode中尝试了硬编码,它立即返回了一个列表

    SELECT A.SL_STORENUM,A.Sl_Zip,Q.SL_STORENUM FROM tbl_store_locations AS A
    CROSS APPLY (SELECT SL_StoreNum FROM tbl_store_locations WHERE SL_Zip in (select zipnum from udf_GetLongLatDist('12345',7))) AS Q 
    WHERE A.SL_StoreNum='04'
    

    完成此附近地点列表的最有效方法是什么?我在这里使用“04”作为示例时要记住,我想对2,000个位置进行分析。

    “udf_GetLongLatDist”是一个函数,它使用一些数学计算两个地理坐标之间的距离,并返回一个距离为>的zipcodes列表。 0.没有什么花哨的。

3 个答案:

答案 0 :(得分:1)

使用此功能时,您可能需要计算每行的每个可能距离。这就是为什么需要这么长时间。实际物理位置通常不会移动,我们一直在做的是预先计算每个邮政编码到其他所有邮政编码的距离(当我们添加新的可能的邮政编码时,每月只更新一次)。一旦预先计算了距离,您所要做的就是运行像

这样的查询
select zip2 from zipprecalc where zip1 = '12345' and distance <=10

答案 1 :(得分:1)

我们有类似的东西并通过仅计算纬度在有界范围内的其他zipcodes的距离来优化它。因此,如果你想在@miles中使用其他拉链,你可以使用

where latitude >= @targetLat - (@miles/69.2) and latitude <= @targetLat + (@miles/69.2)

然后,您只计算其他邮政编码行的更小子集的大圆距离。我们在使用中发现这个速度足够快,不需要预先计算。

同样的事情不能用于经度,因为赤道和极点之间的差异是经度表示的距离。

答案 2 :(得分:0)

此处的其他答案涉及重新算法。我个人建议所有拉链码相互预先计算好的地图。应该可以在现有的udf中嵌入这样的优化,以最大限度地减少代码更改。

然而,查询的重构可以如下......

SELECT
  A.SL_STORENUM, A.Sl_Zip, C.SL_STORENUM
FROM
  tbl_store_locations                 AS A
CROSS APPLY
  dbo.udf_GetLongLatDist(A.Sl_Zip,7)  AS B
INNER JOIN
  tbl_store_locations                 AS C
    ON C.SL_Zip = B.zipnum
WHERE
  A.SL_StoreNum='04'

此外,如果您可以确保udf是INLINE而不是MULTI-STATEMENT,那么CROSS APPLY的性能将大大受益。这允许udf内联扩展(像宏一样),以实现更清晰的执行计划。

这样做还允许您从udf返回其他字段。然后,优化器可以在计划中包含或排除这些字段,具体取决于您是否实际使用它们。如果可以从udf中的查询中轻松访问SL_StoreNum,那么这样的示例就是包含{{1}},因此无需最后一次加入......