Ste*_*eve 6 performance sql-server tuning functions
我有一个查询,用于查找距离已知点 1 公里以内的位置。
为此,我使用了余弦球面定律公式和我的纬度和经度。
目前,该查询在大约 5 分钟内运行了大约 5000 条记录。这是可以接受的,但我想尽快完成。
我使用的主要查询:
select loc.*, base.key
from locations loc left outer join baseline base
on base.key in
(select key
from baseline
where [dbo].CIRCLEDISTANCE(loc.LAT, base.LATITUDE, loc.LONG, base.LONGITUDE) <= 1)
Run Code Online (Sandbox Code Playgroud)
圆距离标量值函数:
ALTER FUNCTION CIRCLEDISTANCE
(
-- Add the parameters for the function here
@LAT1 varchar(250),
@LAT2 varchar(250),
@LNG1 varchar(250),
@LNG2 varchar(250)
)
RETURNS float
AS
BEGIN
DECLARE @Distance float
DECLARE @LAT1_FLOAT float
DECLARE @LNG1_FLOAT float
DECLARE @LAT2_FLOAT float
DECLARE @LNG2_FLOAT float
select @LAT1_FLOAT = cast(@LAT1 as float)
select @LNG1_FLOAT = cast(@LNG1 as float)
select @LAT2_FLOAT = cast(@LAT2 as float)
select @LNG2_FLOAT = cast(@LNG2 as float)
SELECT @Distance = acos(sin(radians(@LAT1_FLOAT))*
sin(radians(@LAT2_FLOAT))+
cos(radians(@LAT1_FLOAT))*
cos(radians(@LAT2_FLOAT))*
cos(radians(@LNG2_FLOAT)-radians(@LNG1_FLOAT ))
)*6371;
RETURN @Distance
END
GO
Run Code Online (Sandbox Code Playgroud)
我已经索引了查询和函数中命名的所有列。
一些注意事项:
我自己不是 DBA,只是 .net 开发人员,所以我对提高索引以外的查询性能并不真正了解,因此感谢任何帮助。
编辑:
滚动 Rob 和 Mark 的答案使我的查询执行时间缩短到 30 秒。如果有任何进一步的收益,现在是查询:
select <columns>
from locations loc
left outer join baseline base
on base.key in
(select key
from baseline
where base.location_geo.STDistance(loc.location_geo) <= 0.00015678559)
Run Code Online (Sandbox Code Playgroud)
0.00015678559 是 1000/6378137(地球半径),所以当查询运行时我不需要做任何数学运算。
location_geo 是一个使用以下公式的计算列:
([geography]::STGeomFromText(((('POINT('+[Longitude])+' ')+[Latitude])+')',(104001)))
Run Code Online (Sandbox Code Playgroud)
104001 是球形地球模型的空间 ID,因为我不是在寻找很远的距离,这似乎使查询更快地返回。
我在 location_geo 列上也有一个空间索引,如下所示:http : //social.technet.microsoft.com/wiki/contents/articles/9694.tuning-spatial-point-data-queries-in-sql-server- 2012.aspx
创建一个计算列,使用 Point 构造函数将您的 lat 和 long 列转换为地理类型。然后在这个计算列上放置一个空间索引。
然后您的查询可以从您的圆心创建一个地理点,并比较距离。应该非常快。
标量值函数需要时间来调用,并且从它的外观来看,您正在对CIRCLEDISTANCE. 您可以将函数重写为内联表值函数。
create function CIRCLEDISTANCE
(
@LAT1 varchar(250),
@LAT2 varchar(250),
@LNG1 varchar(250),
@LNG2 varchar(250)
)
returns table as return
(
select acos(sin(radians(cast(@LAT1 as float)))*
sin(radians(cast(@LAT2 as float)))+
cos(radians(cast(@LAT1 as float)))*
cos(radians(cast(@LAT2 as float)))*
cos(radians(cast(@LNG2 as float))-radians(cast(@LNG1 as float)))
)*6371 as Distance
)
Run Code Online (Sandbox Code Playgroud)
这需要稍微重写您的主查询,因为该函数现在返回一个表而不是标量值。
select loc.*,
B.[key]
from locations as loc
outer apply (
select base.[key]
from baseline as base
cross apply dbo.CIRCLEDISTANCE2(loc.LAT, base.LATITUDE, loc.LONG, base.LONGITUDE) as C
where C.Distance <= 1
group by base.[key]
) as B
Run Code Online (Sandbox Code Playgroud)