首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 經緯度計算距離標量函數:Haversine 公式完整實現 (公里/米可配置)

     編輯:關於SqlServer

Haversine 公式原理

球面兩點最短距離 (大圓距離): d = 2R × arcsin(√(sin²(Δφ/2) + cos φ1 × cos φ2 × sin²(Δλ/2)))

  • φ = 緯度 (radians),λ = 經度 (radians)
  • R = 地球半徑 ≈ 6371 km (或 6378.137 km 赤道半徑)

標量函數完整代碼

CREATE FUNCTION dbo.fn_GetDistance
(
    @LatBegin FLOAT,  -- 起點緯度
    @LngBegin FLOAT,  -- 起點經度
    @LatEnd   FLOAT,  -- 終點緯度
    @LngEnd   FLOAT   -- 終點經度
)
RETURNS FLOAT
AS
BEGIN
    DECLARE @EarthRadius FLOAT = 6371.0;  -- 公里,改 6371000 為米
    DECLARE @RadLat1 FLOAT = RADIANS(@LatBegin);
    DECLARE @RadLat2 FLOAT = RADIANS(@LatEnd);
    DECLARE @RadLng1 FLOAT = RADIANS(@LngBegin);
    DECLARE @RadLng2 FLOAT = RADIANS(@LngEnd);
    
    DECLARE @DLat FLOAT = @RadLat1 - @RadLat2;
    DECLARE @DLng FLOAT = @RadLng1 - @RadLng2;
    
    DECLARE @A FLOAT = SIN(@DLat/2) * SIN(@DLat/2) 
                     + COS(@RadLat1) * COS(@RadLat2) 
                     * SIN(@DLng/2) * SIN(@DLng/2);
    
    DECLARE @C FLOAT = 2 * ATN2(SQRT(@A), SQRT(1-@A));  -- 2*asin(sqrt(a)) 等價
    -- SQL Server 無 ASIN,用 ATN2(x, sqrt(1-x^2)) 替代
    
    RETURN @EarthRadius * @C;  -- 公里
END;
GO

使用範例

-- 台北車站 (25.0478, 121.5170) → 高雄車站 (22.6300, 120.3000)
SELECT dbo.fn_GetDistance(25.0478, 121.5170, 22.6300, 120.3000) AS Distance_KM;
-- 結果約 340 公里

-- 就近查詢:找 5 公里內門市
DECLARE @MyLat FLOAT = 25.0478, @MyLng FLOAT = 121.5170;
SELECT *, dbo.fn_GetDistance(@MyLat, @MyLng, Lat, Lng) AS Dist_KM
FROM Stores
WHERE dbo.fn_GetDistance(@MyLat, @MyLng, Lat, Lng) <= 5
ORDER BY Dist_KM;

⚠️ 效能優化關鍵 (大資料量必讀)

  1. 標量函數逐行執行極慢:百萬行查詢會調用百萬次函數 → 改用 內嵌表值函數 (iTVF) 或直接展開運算式
  2. 空間索引 (SQL Server 2008+):geography 型別 + STDistance 原生支援空間索引
    ALTER TABLE Stores ADD GeoLoc AS geography::Point(Lat, Lng, 4326) PERSISTED;
    CREATE SPATIAL INDEX idx_geo ON Stores(GeoLoc);
    SELECT * FROM Stores WHERE GeoLoc.STDistance(geography::Point(@MyLat, @MyLng, 4326)) <= 5000; -- 米
        
  3. 邊界框預過濾:先用經緯度範圍粗略過濾 (矩形),再精確計算
    WHERE Lat BETWEEN @MyLat - 0.05 AND @MyLat + 0.05
      AND Lng BETWEEN @MyLng - 0.05 AND @MyLng + 0.05
      AND dbo.fn_GetDistance(...) <= 5
        

精度對比

方法精度效能支援索引
Haversine 標量函數高 (米級)低❌
geography STDistance極高 (毫米級)中 (有索引時極快)✅ 空間索引
平面近似 (小範圍)中 (百米級)極高✅ B-Tree
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved