我正在尝试将表类型传递给存储过程,并希望sproc查找lat / longs的每一行并返回该行的最近点。
类型:
CREATE TYPE dbo.LatLongRoadLinkType AS TABLE
(
Id INT NOT NULL,
Latitude FLOAT NOT NULL,
Longitude FLOAT NOT NULL
);
存储过程:
ALTER PROCEDURE [dbo].[BatchNearestRoadNodes]
@Input dbo.LatLongRoadLinkType READONLY
AS
BEGIN
-- do stuff here
-- return a table of id from input, nodeid and distance
END
对于整个表格,这里需要做的是单个纬度/经度:
DECLARE @g geography = 'POINT(13.5333414077759 54.549524307251)';
DECLARE @region geography = @g.STBuffer(5000)
SELECT TOP 1 NodeID, Point.STDistance(@g) as 'Distance'
FROM Location
WHERE Point.Filter(@region) = 1
ORDER BY Point.STDistance(@g)
Location表有重要的Point类型Geography,它是空间索引的,是比较完成的。我将lat / longs表从代码发送到sproc中,代码期待返回of:
Id (original point passed in)
NodeID (of nearest point in location table)
Distance
我该如何处理?为了让它更容易一点,我可以简单地将SqlGeography从我的代码传递到sproc而不是Lat / Long,但是这会导致性能下降,因为它转换成非常昂贵的。
修改: 这有效,但不知道它是否是最佳解决方案。
ALTER PROCEDURE [dbo].[BatchNearestRoadNodes]
@Input dbo.LatLongRoadLinkType READONLY
AS
BEGIN
SELECT x.Id, x.LocationName, x.NodeID, x.Distance
FROM (SELECT I.Id,
L.LocationName,
L.NodeId,
L.Point.STDistance(geography::Point(I.Latitude, I.Longitude, 4326)) AS Distance,
ROW_NUMBER () OVER (PARTITION BY I.Id ORDER BY L.Point.STDistance(geography::Point(I.Latitude, I.Longitude, 4326)) ASC) AS Ranking
FROM @Input AS I
JOIN Location AS L
ON L.Point.STIntersects(geography::Point(I.Latitude, I.Longitude, 4326).STBuffer(5000)) = 1
) AS x WHERE Ranking = 1
END
效果 - V1与Jon的编辑
V1
============
original:643 found:627 in:1361 ms
original:1018 found:999 in:1700 ms
original:1801 found:1758 in:2628 ms
original:4098 found:3973 in:5271 ms
original:16388 found:15948 in:19624 ms
Jon's Edit
==========
original:643 found:627 in:1333 ms
original:1018 found:999 in:1689 ms
original:1801 found:1758 in:2559 ms
original:4098 found:3973 in:5114 ms
original:16388 found:15948 in:19054 ms
差异很小。需要得到最后一个数字。
答案 0 :(得分:0)
尝试这样的方法来获得部分结果:
WITH PreQuery AS
(
I.Id,
GEOGRAPHY::STPointFromText(I.PointAsWKT).STBuffer(5000) AS Geog,
L.NodeId,
L.Point
FROM
@Input AS I
JOIN
Location AS L ON L.Point.STIntersects(I.Geog) = 1
)
SELECT
P.Id,
P.NodeId,
P.Geog.STDistance(P.Point) AS Distance
FROM
PreQuery P
我是从头上写下来的,没有任何测试数据,所以可能会有小错误,但主要是它会给你每个节点和它距离每个点的距离(在5000米内) 。你仍然需要过滤它们以获得每个id最小距离的那个 - 不应该太难; - )
希望它有所帮助,即使不完整。
编辑(12月2日)
我已经看到了我的第一个解决方案的问题,你无法获得距离,因为它是预先缓冲的(注意主要的事情)。但是,这种合并应该是两种尝试的最有效组合。
WITH PreQuery AS
(
SELECT
I.Id,
geography::Point(I.Latitude, I.Longitude, 4326) AS InputGeography
FROM
@input AS I
)
SELECT x.Id, x.LocationName, x.NodeId, x.Distance
FROM
(
SELECT
PQ.Id,
L.LocationName,
L.NodeId,
L.Point.STDistance(PQ.InputGeography) AS Distance,
ROWNUMBER() OVER (PARTITION BY I.Id ORDER BY L.Point.Distance(PQ.InputGeography) ASC) AS Ranking
FROM
Prequery AS PQ
JOIN
Location AS L
-- ON L.Point.STIntersects(PQ.InputGeography.STBuffer(5000)) = 1 -- Slower
ON L.Point.STDistance(PQ.InputGeography) <= 5000 -- Faster
) AS X WHERE Ranking = 1
这样,您只需预先创建输入地理位置一次,而不是根据您的尝试创建三次。这是未经测试的,但应该证明是最有效的。