2

SQL Server 2008 R2 Express データベースには約 7,500 万のレコードがあります。それぞれは、ある値に対応する緯度経度です。テーブルには geography 列があります。特定の緯度経度 (ポイント) の最近傍を見つけようとしています。空間インデックスを使用したクエリが既にあります。ただし、レコードがデータベース内のどこにあるか (たとえば、第 1 四半期か前四半期か) によっては、クエリが最近傍を見つけるのに約 3 秒から 30 秒かかる場合があります。クエリまたは空間インデックスを最適化することで、これを最適化してより高速な結果を得ることができると思います。現在、デフォルト設定でいくつかの空間インデックスを適用しています。これが私のテーブルとクエリの外観です。

CREATE TABLE lidar(
    [id] [bigint] IDENTITY(1,1) NOT NULL,
    [POINTID] [int] NOT NULL,
    [GRID_CODE] [numeric](17, 8) NULL,
    [geom] [geography] NULL,
 CONSTRAINT [PK_lidar_1] PRIMARY KEY CLUSTERED ([id] ASC)
 WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, 
 ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

私が使用している空間インデックス:

CREATE SPATIAL INDEX [SPATIAL_lidar] ON [dbo].[lidar] ([geom]) USING  GEOGRAPHY_GRID 
WITH (
GRIDS =(LEVEL_1 = MEDIUM,LEVEL_2 = MEDIUM,LEVEL_3 = MEDIUM,LEVEL_4 = MEDIUM), 
CELLS_PER_OBJECT = 16, PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF,  
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

私が使用しているクエリは次のとおりです。

declare @ms_at geography = 'POINT (-95.66 30.04)';
select TOP(1) nearPoints.geom.STAsText()as latlon 
from
(
select r.geom
from lidar r With(Index(SPATIAL_lidar))
where r.geom.STIntersects(@ms_at.STBuffer(1000)) = 1
) nearPoints

これは、私のデータベースの緯度経度のサンプルです。精度と密度のアイデアを提供します。7,000 万件のレコードはすべて 1 つの都市のものです (Lidar データ)

POINT (-95.669434934023087 30.049513838913736)

このクエリでは、上記の結果が得られますが、パフォーマンスを可能な限り改善したいと考えています。私の推測では、空間インデックスのデフォルト値を微調整することで、パフォーマンスを改善できる可能性があります。何か手がかりはありますか?

バッファを 10 から 1000 まで変えてみましたが、結果はほぼ同じでした。

また、パフォーマンスを改善するためのその他の提案も歓迎します。

私が現在使用しているシステムは次のとおりです。

Windows 7 64bit Professional
Intel(R) Core(TM)2 Quad CPU    Q9650  @ 3.00GHz (4 CPUs), ~3.0GHz
Ram: 8 GB
NVIDIA GeForce 9500 GT
4

4 に答える 4

2

申し訳ありませんが、これは SQL の回答ではなく、データに対する特定の制約を想定して予測可能なパフォーマンスを得る方法です。

データはどのくらいの頻度で変更されますか? 可能であれば、すべてのエンティティ 5 つの最近傍のグラフを事前に計算し、それを使用して選択を高速化できますか?

このデータがほとんど読み取り専用の場合は...

これらのポイントはどの程度均等に分布していますか? 分散がかなり均等でよくわかっている場合は、ハッシュ テーブル内のすべての座標とインデックスをバケット化して、独自の空間マッピングを作成できます。

データベースにデータを保持する必要がない場合は、高速なハッシュ ルックアップのために、データをメモリ マップ ファイルに移動します。(70m のレコードはメモリに簡単に収まるはずです)。

私はこのアーキテクチャを使用して、ディスプレイ広告と検索エンジンの関連性のためにサブミリ秒のルックアップを生成しました。

==詳細==

固定サイズの正方形 (チェス盤のような) のグリッドを作成し、各点をグリッドにマッピングし、各グリッド ボックスに属するオブジェクトのリストを作成します。それぞれのサイズを調整すると、ボックスを正しく選択すると、平均して各正方形に 5 ~ 50 個のポイントが含まれるはずです。これは原則として四分木ですが、単純にするために木はありません。

バケット内のすべてのデータを分散させた後に空のバケットごとに、データを含む最も近いバケットの情報を追加します。

各バケットに、座標から計算できる一意の番号が付けられるように、各バケットに左から右の行に番号を付けることができます。また、各バケットをハッシュ テーブルに挿入するか、スペースが許す場合はストレート ルックアップ テーブル。

クエリを取得したら、マップするバケットを計算するだけで、そのバケット内のオブジェクトのリストを取得するか、コンテンツを持つ最も近いバケットへのポインターを含む「空の」バケットを取得します.

これにより、探しているオブジェクトの最初の候補リストが得られます。あとは、実行して最も近いオブジェクトを確認するだけです。

99% のケースではそうです -- しかし、(a) 次のバケツに実際により近いいくつかの候補があることを心配している場合は、周囲の 8 つのバケツをチェックして、できるかどうかを確認してください。そこに近いものを見つけてください。

最も近いすべてのオブジェクトのリストも取得したい場合は、オブジェクトごとに 5 つの最近隣の単純なネットワークも計算すると、A->{B,C,D のようなデータ構造になります。 ,E,F}, B->{A,D,G,H,I}, C->{A,J,K,G,M}....

これにより、最も近いポイントに隣接するすべてのポイントを取得するために、ここでDijkstraのバリエーションを使用してトラバースできる単純なネットワークが形成されます。

データ構造の構築には時間がかかりますが、一度完了すると、適切なルックアップが完了してデータセットを返すことは、ミリ秒未満で実行できます (原因による http またはオフボックス通信は含まれません)。

お役に立てれば。

于 2011-07-11T20:43:06.010 に答える
0

インデックス設定をいじってみましたか?私は通常、セルごとに高いオブジェクトを使用し、すべてのグリッド レベルで「高い」オブジェクトを使用します。下記参照:

CREATE SPATIAL INDEX [SPATIAL_lidar] ON [dbo].[lidar] ([geom]) USING  GEOGRAPHY_GRID  WITH ( GRIDS =(LEVEL_1 =   HIGH,LEVEL_2 = HIGH,LEVEL_3 = HIGH,LEVEL_4 = HIGH),  CELLS_PER_OBJECT = 64, PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF,   ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY] 
于 2011-07-13T08:23:57.233 に答える
0

SQL Server 2008 での通常の最近傍クエリについては、Isaac が彼のブログで説明しているアプローチを試してください。これは、数値テーブルを使用して、十分な候補が見つかるまでルックアップの境界を増やします。もう 1 つの推奨事項は、グリッド密度を変えてみることです。HHHH または HHMM は、密度の高いポイントに対してより適切に機能する可能性があります。

Sql Server Denali では、最適化された最近傍クエリのこの機能も、通常の SELECT TOP ... ORDER BY 構文を使用してネイティブにサポートされます。

補足として、あなたの例では、クエリに ORDER BY 距離句が欠落しているように見えます。現在のクエリは、ターゲットから 1000 メートル以内のポイントを返しますが、必ずしも最も近いポイントではありません。

于 2011-07-12T14:14:23.380 に答える