关于已知经纬度查找周围两公里的用户

jovien 2017-08-14 09:40:19
已知user表,有uid,name,lon,lat,online(bit,0离线,1在线)移动端心跳包发过来的经纬度,一分钟更新一次。

现在需要用一个存储过程,用当前发过来的@lon,@lat 作为参数找出周围2公里在线的用户,返回一个TABLE。

要求效率高一点,有可能在线用户有几万。


跪求各路大神
...全文
341 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
jovien 2017-08-15
  • 打赏
  • 举报
回复
引用 9 楼 zengertao 的回复:
[quote=引用 6 楼 jovien 的回复:] [quote=引用 3 楼 zengertao 的回复:] [quote=引用 2 楼 jovien 的回复:] [quote=引用 1 楼 sinat_28984567 的回复:] 试试这个:
CREATE PROC dbo.getDistance
    @lon decimal(10,6),
    @lat  decimal(10,6)
AS
    BEGIN
        SELECT  *
        FROM    [User]
        WHERE   (Geography::Point(@lat, @lon, 4326) .STDistance(( Geography::Point(lat,
                                                              lon, 4326) ))
                / 1000) < 2
                AND [online] = 1;
    END;
GO

SELECT  uid,name,lon,lat,(Geography::Point(30.606311,114.253424,4326) .STDistance(( Geography::Point(lat,lon, 4326) ))/ 1000) as jl
        FROM    [users]
        WHERE   [online] = 1 and (Geography::Point(30.606311,114.253424,4326) .STDistance(( Geography::Point(lat,lon, 4326) ))/ 1000)<2 order by jl desc;
如果我同时把距离拉出来,像我这样计算好像不行,距离计算了两次,有什么办法可以避免吗? 我测试了一下,从10W行里检索到7W行,你的方法只需要1.4秒,而我这样增加一列需要2秒,消耗增加不少啊。 多谢大神指导。 [/quote]
CREATE PROC dbo.getDistance
    @lon decimal(10,6),
    @lat  decimal(10,6)
AS
    BEGIN
    	SELECT uid,name,lon,lat,c1 FROM (
			SELECT  uid,name,lon,lat,(Geography::Point(@lat, @lon, 4326) .STDistance(( Geography::Point(lat,lon, 4326) ))/ 1000) AS c1
			FROM    [User]
			WHERE   [online] = 1
    	) tt
    	WHERE tt.c1<2
    END;
GO
你可以尝试再套一层,当然如果原始数据量比过滤后大很多的话,肯定还是你2#的计算2次更效率。这样做只是纯粹少计算一次罢了。[/quote] 套一层,我试了下,实际差距不大,都还是稳定在2秒左右[/quote] 这样我建议如果需要查询出来这个字段的话,采用你自己2#的计算2次语句。[/quote] 是的,我也是准备这么处理,实际生产数据WHERE过滤之后已经所剩无几了
繁花尽流年 2017-08-15
  • 打赏
  • 举报
回复
引用 6 楼 jovien 的回复:
[quote=引用 3 楼 zengertao 的回复:] [quote=引用 2 楼 jovien 的回复:] [quote=引用 1 楼 sinat_28984567 的回复:] 试试这个:
CREATE PROC dbo.getDistance
    @lon decimal(10,6),
    @lat  decimal(10,6)
AS
    BEGIN
        SELECT  *
        FROM    [User]
        WHERE   (Geography::Point(@lat, @lon, 4326) .STDistance(( Geography::Point(lat,
                                                              lon, 4326) ))
                / 1000) < 2
                AND [online] = 1;
    END;
GO

SELECT  uid,name,lon,lat,(Geography::Point(30.606311,114.253424,4326) .STDistance(( Geography::Point(lat,lon, 4326) ))/ 1000) as jl
        FROM    [users]
        WHERE   [online] = 1 and (Geography::Point(30.606311,114.253424,4326) .STDistance(( Geography::Point(lat,lon, 4326) ))/ 1000)<2 order by jl desc;
如果我同时把距离拉出来,像我这样计算好像不行,距离计算了两次,有什么办法可以避免吗? 我测试了一下,从10W行里检索到7W行,你的方法只需要1.4秒,而我这样增加一列需要2秒,消耗增加不少啊。 多谢大神指导。 [/quote]
CREATE PROC dbo.getDistance
    @lon decimal(10,6),
    @lat  decimal(10,6)
AS
    BEGIN
    	SELECT uid,name,lon,lat,c1 FROM (
			SELECT  uid,name,lon,lat,(Geography::Point(@lat, @lon, 4326) .STDistance(( Geography::Point(lat,lon, 4326) ))/ 1000) AS c1
			FROM    [User]
			WHERE   [online] = 1
    	) tt
    	WHERE tt.c1<2
    END;
GO
你可以尝试再套一层,当然如果原始数据量比过滤后大很多的话,肯定还是你2#的计算2次更效率。这样做只是纯粹少计算一次罢了。[/quote] 套一层,我试了下,实际差距不大,都还是稳定在2秒左右[/quote] 这样我建议如果需要查询出来这个字段的话,采用你自己2#的计算2次语句。
jovien 2017-08-15
  • 打赏
  • 举报
回复
引用 7 楼 sinat_28984567 的回复:
[quote=引用 5 楼 jovien 的回复:] @sinat_28984567 你的意思是,其实这个计算本身是没有多大消耗的是吧,多计算一次比多筛选一次来得更快。
不是,where筛选可以过滤掉很多数据的,能先通过where 、on 等过滤的要先这样过滤……[/quote] 明白了,WHERE 里先过滤掉大部分数据之后,别名列再计算其实量就已经相当少了,正常的生产数据,可能WHERE过滤完之后就只剩下几十或几百条而已
二月十六 2017-08-15
  • 打赏
  • 举报
回复
引用 5 楼 jovien 的回复:
@sinat_28984567 你的意思是,其实这个计算本身是没有多大消耗的是吧,多计算一次比多筛选一次来得更快。
不是,where筛选可以过滤掉很多数据的,能先通过where 、on 等过滤的要先这样过滤……
jovien 2017-08-15
  • 打赏
  • 举报
回复
引用 3 楼 zengertao 的回复:
[quote=引用 2 楼 jovien 的回复:] [quote=引用 1 楼 sinat_28984567 的回复:] 试试这个:
CREATE PROC dbo.getDistance
    @lon decimal(10,6),
    @lat  decimal(10,6)
AS
    BEGIN
        SELECT  *
        FROM    [User]
        WHERE   (Geography::Point(@lat, @lon, 4326) .STDistance(( Geography::Point(lat,
                                                              lon, 4326) ))
                / 1000) < 2
                AND [online] = 1;
    END;
GO

SELECT  uid,name,lon,lat,(Geography::Point(30.606311,114.253424,4326) .STDistance(( Geography::Point(lat,lon, 4326) ))/ 1000) as jl
        FROM    [users]
        WHERE   [online] = 1 and (Geography::Point(30.606311,114.253424,4326) .STDistance(( Geography::Point(lat,lon, 4326) ))/ 1000)<2 order by jl desc;
如果我同时把距离拉出来,像我这样计算好像不行,距离计算了两次,有什么办法可以避免吗? 我测试了一下,从10W行里检索到7W行,你的方法只需要1.4秒,而我这样增加一列需要2秒,消耗增加不少啊。 多谢大神指导。 [/quote]
CREATE PROC dbo.getDistance
    @lon decimal(10,6),
    @lat  decimal(10,6)
AS
    BEGIN
    	SELECT uid,name,lon,lat,c1 FROM (
			SELECT  uid,name,lon,lat,(Geography::Point(@lat, @lon, 4326) .STDistance(( Geography::Point(lat,lon, 4326) ))/ 1000) AS c1
			FROM    [User]
			WHERE   [online] = 1
    	) tt
    	WHERE tt.c1<2
    END;
GO
你可以尝试再套一层,当然如果原始数据量比过滤后大很多的话,肯定还是你2#的计算2次更效率。这样做只是纯粹少计算一次罢了。[/quote] 套一层,我试了下,实际差距不大,都还是稳定在2秒左右
jovien 2017-08-15
  • 打赏
  • 举报
回复
@sinat_28984567 你的意思是,其实这个计算本身是没有多大消耗的是吧,多计算一次比多筛选一次来得更快。
二月十六 2017-08-15
  • 打赏
  • 举报
回复
引用 2 楼 jovien 的回复:
[quote=引用 1 楼 sinat_28984567 的回复:] 试试这个:
CREATE PROC dbo.getDistance
    @lon decimal(10,6),
    @lat  decimal(10,6)
AS
    BEGIN
        SELECT  *
        FROM    [User]
        WHERE   (Geography::Point(@lat, @lon, 4326) .STDistance(( Geography::Point(lat,
                                                              lon, 4326) ))
                / 1000) < 2
                AND [online] = 1;
    END;
GO

SELECT  uid,name,lon,lat,(Geography::Point(30.606311,114.253424,4326) .STDistance(( Geography::Point(lat,lon, 4326) ))/ 1000) as jl
        FROM    [users]
        WHERE   [online] = 1 and (Geography::Point(30.606311,114.253424,4326) .STDistance(( Geography::Point(lat,lon, 4326) ))/ 1000)<2 order by jl desc;
如果我同时把距离拉出来,像我这样计算好像不行,距离计算了两次,有什么办法可以避免吗? 我测试了一下,从10W行里检索到7W行,你的方法只需要1.4秒,而我这样增加一列需要2秒,消耗增加不少啊。 多谢大神指导。 [/quote] 没办法吧……sql会先执行where,再执行select,所以select的里边的别名计算列,在where中无法使用
繁花尽流年 2017-08-15
  • 打赏
  • 举报
回复
引用 2 楼 jovien 的回复:
[quote=引用 1 楼 sinat_28984567 的回复:] 试试这个:
CREATE PROC dbo.getDistance
    @lon decimal(10,6),
    @lat  decimal(10,6)
AS
    BEGIN
        SELECT  *
        FROM    [User]
        WHERE   (Geography::Point(@lat, @lon, 4326) .STDistance(( Geography::Point(lat,
                                                              lon, 4326) ))
                / 1000) < 2
                AND [online] = 1;
    END;
GO

SELECT  uid,name,lon,lat,(Geography::Point(30.606311,114.253424,4326) .STDistance(( Geography::Point(lat,lon, 4326) ))/ 1000) as jl
        FROM    [users]
        WHERE   [online] = 1 and (Geography::Point(30.606311,114.253424,4326) .STDistance(( Geography::Point(lat,lon, 4326) ))/ 1000)<2 order by jl desc;
如果我同时把距离拉出来,像我这样计算好像不行,距离计算了两次,有什么办法可以避免吗? 我测试了一下,从10W行里检索到7W行,你的方法只需要1.4秒,而我这样增加一列需要2秒,消耗增加不少啊。 多谢大神指导。 [/quote]
CREATE PROC dbo.getDistance
    @lon decimal(10,6),
    @lat  decimal(10,6)
AS
    BEGIN
    	SELECT uid,name,lon,lat,c1 FROM (
			SELECT  uid,name,lon,lat,(Geography::Point(@lat, @lon, 4326) .STDistance(( Geography::Point(lat,lon, 4326) ))/ 1000) AS c1
			FROM    [User]
			WHERE   [online] = 1
    	) tt
    	WHERE tt.c1<2
    END;
GO
你可以尝试再套一层,当然如果原始数据量比过滤后大很多的话,肯定还是你2#的计算2次更效率。这样做只是纯粹少计算一次罢了。
jovien 2017-08-15
  • 打赏
  • 举报
回复
引用 1 楼 sinat_28984567 的回复:
试试这个:
CREATE PROC dbo.getDistance
    @lon decimal(10,6),
    @lat  decimal(10,6)
AS
    BEGIN
        SELECT  *
        FROM    [User]
        WHERE   (Geography::Point(@lat, @lon, 4326) .STDistance(( Geography::Point(lat,
                                                              lon, 4326) ))
                / 1000) < 2
                AND [online] = 1;
    END;
GO

SELECT  uid,name,lon,lat,(Geography::Point(30.606311,114.253424,4326) .STDistance(( Geography::Point(lat,lon, 4326) ))/ 1000) as jl
        FROM    [users]
        WHERE   [online] = 1 and (Geography::Point(30.606311,114.253424,4326) .STDistance(( Geography::Point(lat,lon, 4326) ))/ 1000)<2 order by jl desc;
如果我同时把距离拉出来,像我这样计算好像不行,距离计算了两次,有什么办法可以避免吗? 我测试了一下,从10W行里检索到7W行,你的方法只需要1.4秒,而我这样增加一列需要2秒,消耗增加不少啊。 多谢大神指导。
二月十六 2017-08-14
  • 打赏
  • 举报
回复
试试这个:
CREATE PROC dbo.getDistance
@lon decimal(10,6),
@lat decimal(10,6)
AS
BEGIN
SELECT *
FROM [User]
WHERE (Geography::Point(@lat, @lon, 4326) .STDistance(( Geography::Point(lat,
lon, 4326) ))
/ 1000) < 2
AND [online] = 1;
END;
GO

27,580

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 应用实例
社区管理员
  • 应用实例社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧