2

データベースに緯度と経度の座標が保存されている場所があるプロジェクトに取り組んでいます。私はGoogleマップを使用して、これらの場所を地図上のマーカーとしてプロットします。「非表示」のマーカー(現在のビューポート/バウンディングボックスの外側のマーカー)をマップにプロットしたくありません。したがって、ビューポートマーカーの管理に関するGoogleのアドバイスに従います。

マップのビューポートが変更されるたびに、AJAXを使用してASP.NETWebサービスにクエリを実行する実用的なソリューションがあります。このWebサービスは、MSSQLデータベースのストアドプロシージャを呼び出して、現在のビューポート/バウンディングボックス内にある座標を持つすべての場所を取得します。ストアドプロシージャは次のようになります。

ALTER PROCEDURE dbo.GetPlacesInsideBoundingBox

    (
    @swLat VarChar(11), /* south-west point latitude */
    @swLng VarChar(11), /* south-west point longitude */
    @neLat VarChar(11), /* north-east point latitude */
    @neLng VarChar(11) /* north-east point longitude */
    )

AS
    /* SET NOCOUNT ON */

    SELECT * FROM dbo.Place WHERE 
    place_lat >= CONVERT(Decimal(11,8), @swLat) 
    AND place_lat <= CONVERT(Decimal(11,8), @neLat) 
    AND place_lng >= CONVERT(Decimal(11,8), @swLng)  
    AND place_lng <= CONVERT(Decimal(11,8), @neLng)
    RETURN

ストアドプロシージャに送信されるパラメータは、ビューポート/バウンディングボックスの南西と北東の角の緯度と経度です。次に、これらのポイントをデータベースに保存されている経度と緯度の値と比較して、現在のビューポート/バウンディングボックス内にある場所を確認します。

これは問題なく動作します!しかし、経度(本初子午線の西)の値が負の場合は問題が発生する可能性があり、単純な解決策は経度が負の場合は経度に360を追加することであると読みました。

2つの質問があります:

  1. 負の経度を考慮に入れるために、ストアドプロシージャ(上記)を変更するにはどうすればよいですか?

  2. このストアドプロシージャを確実に実行するために、他に検討すべき変更はありますか?

VarCharからDecimalへの変換について疑問がある場合は、クライアント側で単純な文字列(javascript)を操作し、計算が必要になったときにストアドプロシージャでそれらを10進数に変換する方がはるかに簡単であることがわかりました。

前もって感謝します!

4

2 に答える 2

1

1)経度は通常-180から180の間でなければならないので、グーグルからの座標がこの条件を満たすかどうかを確認してください。おそらくそうだ。そうでない場合は、360を加算または減算して、この間隔内にあるように正規化します。ストアドプロシージャを呼び出す前に、正規化します。

2)通常@swLng <= @neLngですが、ケースも処理する必要があります@swLng > @neLng。したがって、ストアドプロシージャ内では、経度の条件は次のようになります。

AND 
(
    (CONVERT(Decimal(11,8), @swLng) <= CONVERT(Decimal(11,8), @neLng)
        AND place_lng >= CONVERT(Decimal(11,8), @swLng) 
        AND place_lng <= CONVERT(Decimal(11,8), @neLng)
    ) 
    OR 
    (CONVERT(Decimal(11,8), @swLng) > CONVERT(Decimal(11,8), @neLng)
        AND (place_lng >= CONVERT(Decimal(11,8), @swLng) 
             OR place_lng <= CONVERT(Decimal(11,8), @neLng))
    )
)

PS:これを本当に効率的にするには、おそらくPostGISのようなGISを使用する必要があることに注意してください:)この問題を解決しようとしていましたが、「GISができるまで」延期しました。あなたは私にインスピレーションを与えました、そして多分私もこの解決策に行きます。

PS:データベースエンジンがどのように最適化されるかはわかりませんが、緯度と経度をインデックスとして定義すると、効率が向上する可能性があります。これにより、条件をより迅速に解決できますしかし、私にはまったくわかりません。

于 2011-11-29T13:29:29.687 に答える
1

実際、私はより良い解決策を見つけました。SQL Serverには、空間データを操作するための組み込みのデータ型があります。そこで、テーブルに新しい値を追加し、データ型geographyでplace_geoと呼びました。次に、地理ポイント(データベースに既にある緯度と経度から作成)を入力しました。ポイントを地理ポイントとしてデータベースに保存すると、ストアドプロシージャの構文がはるかに単純になり、実行速度も大幅に向上すると思います。

これが私のストアドプロシージャです:

ALTER PROCEDURE dbo.GetPlaceClosestToMe
    (
    @my_lat Decimal(11,8),
    @my_lng Decimal(11,8)
    )
AS
    DECLARE @my_point geography;
    SET @my_point = geography::Point(@my_lat, @my_lng , 4326); /* SRID 4326 */
    SET NOCOUNT ON

    SELECT TOP 1 
        place_id, 
        place_name,
        @my_point.STDistance(place_geo)/1000 [Distance in km]
FROM Places
ORDER BY @my_point.STDistance(place_geo)

それで、それは何をしますか?まず、経度と緯度を10進形式の入力パラメーターとして取得します。データ型が「geography」の新しい変数(@my_point)を宣言します。次に、経度と緯度の入力パラメータを使用して作成した変数に新しい地理ポイントを割り当てます。

次に、@ my_pointに最も近いデータベーステーブル(place_geo)のポイントを要求します。(STDistanceは、2つの地理タイプ間の最短線を返します。)1000で除算すると、距離がキロメートルで表されます。

複数の結果を返すようにする場合は、selectTOP5またはSELECTTOP10を変更するだけです。

現時点では、これが古い方法を使用するよりも速いかどうかをテストするのに十分なテストデータがありませんが、おそらく他の誰かがいくつかのテストを行っていますか?地理データ型を使用すると、古い方法よりもはるかに高速になると思います。

私の限られたテストデータでは、古いストアドプロシージャとこの新しいストアドプロシージャは同じ結果を返します。

このフォローアップがお役に立てば幸いです。

于 2011-12-05T16:21:09.553 に答える