12

私は、扱っているデータ セットに対して適切な SQL Server 2008 空間インデックスのセットアップを選択しようとしています。

データセットは、地球全体の等高線を表すポリゴンです。テーブルには 106,000 行あり、ポリゴンはジオメトリ フィールドに格納されています。

私が抱えている問題は、多くのポリゴンが地球の大部分をカバーしていることです。これにより、プライマリ フィルターで多くの行を除外する空間インデックスを取得することが非常に難しくなっているようです。たとえば、次のクエリを見てください。

SELECT "ID","CODE","geom".STAsBinary() as "geom" FROM "dbo"."ContA"
WHERE "geom".Filter(
  geometry::STGeomFromText('POLYGON ((-142.03193662573682 59.53396984952896,
    -142.03193662573682 59.88928136451884,
    -141.32743833481925 59.88928136451884,
    -141.32743833481925 59.53396984952896,
    -142.03193662573682 59.53396984952896))', 4326)
) = 1

これは、テーブル内の 2 つのポリゴンのみと交差する領域をクエリしています。選択した空間インデックス設定の組み合わせに関係なく、その Filter() は常に約 60,000 行を返します。

もちろん、Filter() を STIntersects() に置き換えると、必要な 2 つのポリゴンだけが返されますが、当然、はるかに時間がかかります (Filter() は 6 秒、STIntersects() は 12 秒)。

60,000 行で改善される可能性が高い空間インデックスのセットアップがあるかどうか、または私のデータセットが SQL Server の空間インデックスとうまく一致しないかどうかについて、誰かヒントを教えてもらえますか?

より詳しい情報:

示唆されたように、世界中の 4x4 グリッドを使用して、ポリゴンを分割しました。QGIS でそれを行う方法が見つからなかったので、それを行うための独自のクエリを作成しました。最初に 16 個のバウンディング ボックスを定義しました。最初のボックスは次のようになりました。

declare  @box1 geometry = geometry::STGeomFromText('POLYGON ((
-180 90,
-90 90,
-90 45,
-180 45,
-180 90))', 4326)

次に、各境界ボックスを使用して、そのボックスと交差するポリゴンを選択して切り捨てました。

insert ContASplit
select CODE, geom.STIntersection(@box1), CODE_DESC from ContA
where geom.STIntersects(@box1) = 1

明らかに、4x4 グリッドの 16 個のバウンディング ボックスすべてに対してこれを行いました。最終結果は、約 107,000 行の新しいテーブルを作成したことです (これは、実際には多くの巨大なポリゴンがないことを確認しています)。

オブジェクトごとに 1024 セルの空間インデックスを追加し、レベルごとのセルには低、低、低、低を追加しました。

ただし、非常に奇妙なことに、分割されたポリゴンを含むこの新しいテーブルは、古いテーブルと同じように機能します。上記の .Filter を実行しても、最大60,000 行が返されます。私はこれをまったく理解していません。明らかに、空間インデックスが実際にどのように機能するかを理解していません。

逆説的に、.Filter() はまだ 60,000 行を返しますが、パフォーマンスは向上しています。.Filter() は 6 秒ではなく約 2 秒かかり、.STIntersects() は 12 秒ではなく 6 秒かかるようになりました。

ここで要求されているのは、インデックスの SQL の例です。

CREATE SPATIAL INDEX [contasplit_sidx] ON [dbo].[ContASplit] 
(
    [geom]
)USING  GEOMETRY_GRID 
WITH (
BOUNDING_BOX =(-90, -180, 90, 180),
GRIDS =(LEVEL_1 = LOW,LEVEL_2 = LOW,LEVEL_3 = LOW,LEVEL_4 = LOW), 
CELLS_PER_OBJECT = 1024,
PAD_INDEX  = OFF,
SORT_IN_TEMPDB = OFF,
DROP_EXISTING = OFF,
ALLOW_ROW_LOCKS  = ON,
ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

覚えていますが、オブジェクトごとにグリッドとセルのさまざまな設定を試しましたが、毎回同じ結果が得られました。

sp_help_spatial_geometry_index を実行した結果は次のとおりです。これは、単一のポリゴンが地球の 1/16 以上を占めていない私の分割データセットです。

Base_Table_Rows 215138 Bounding_Box_xmin -90 Bounding_Box_ymin -180 Bounding_Box_xmax 90 Bounding_Box_ymax 180 Grid_Size_Level_1 64 Grid_Size_Level_2 64 Grid_Size_Level_3 64 Grid_Size_Level_4 64 Cells_Per_Object 16 Total_Primary_Index_Rows 378650 Total_Primary_Index_Pages 1129 Average_Number_Of_Index_Rows_Per_Base_Row 1 Total_Number_Of_ObjectCells_In_Level0_For_QuerySample 1 Total_Number_Of_ObjectCells_In_Level0_In_Index 60956 Total_Number_Of_ObjectCells_In_Level1_In_Index 361 Total_Number_Of_ObjectCells_In_Level2_In_Index 2935 Total_Number_Of_ObjectCells_In_Level3_In_Index 32420 Total_Number_Of_ObjectCells_In_Level4_In_Index 281978 Total_Number_Of_Interior_ObjectCells_In_Level2_In_Index 1 Total_Number_Of_Interior_ObjectCells_In_Level3_In_Index 49 Total_Number_Of_Interior_ObjectCells_In_Level4_In_Index4236 Total_Number_Of_Intersecting_ObjectCells_In_Level1_In_Index 29 Total_Number_Of_Intersecting_ObjectCells_In_Level2_In_Index 1294 Total_Number_Of_Intersecting_ObjectCells_In_Level3_In_Index 29680 Total_Number_Of_Intersecting_ObjectCells_In_Level4_In_Index 251517 Total_Number_Of_Border_ObjectCells_In_Level0_For_QuerySample 1 Total_Number_Of_Border_ObjectCells_In_Level0_In_Index 60956 Total_Number_Of_Border_ObjectCells_In_Level1_In_Index 332 Total_Number_Of_Border_ObjectCells_In_Level2_In_Index 1640 Total_Number_Of_Border_ObjectCells_In_Level3_In_Index 2691 Total_Number_Of_Border_ObjectCells_In_Level4_In_Index 26225 Interior_To_Total_Cells_Normalized_To_Leaf_Grid_Percentage 0.004852925 Intersecting_To_Total_Cells_Normalized_To_Leaf_Grid_Percentage 0.288147586 Border_To_Total_Cells_Normalized_To_Leaf_Grid_Percentage 99.70699949 Average_Cells_Per_Object_Normalized_To_Leaf_Grid 405.7282349 Average_Objects_PerLeaf_GridCell 0.002464704 Number_Of_SRIDs_Found 1 Width_Of_Cell_In_Level1 2.8125 Width_Of_Cell_In_Level2 0.043945313 Width_Of_Cell_In_Level3 0.000686646 Width_Of_Cell_In_Level4 1.07E-05 Height_Of_Cell_In_Level1 5.625 Height_Of_Cell_In_Level2 0.087890625 Height_Of_Cell_In_Level3 0.001373291 Height_Of_Cell_In_Level4 2.15E-05 Area_Of_Cell_In_Level1 1012.5 Area_Of_Cell_In_Level2 15.8203125 Area_Of_Cell_In_Level3 0.247192383 Area_Of_Cell_In_Level4 0.003862381 CellArea_To_BoundingBoxArea_Percentage_In_Level1 1.5625 CellArea_To_BoundingBoxArea_Percentage_In_Level2 0.024414063 CellArea_To_BoundingBoxArea_Percentage_In_Level3 0.00038147 CellArea_To_BoundingBoxArea_Percentage_In_Level4 5.96E-06 Number_Of_Rows_Selected_By_Primary_Filter 60956 Number_Of_Rows_Selected_By_Internal_Filter 0 Number_Of_Times_Secondary_Filter_Is_Called 60956 Number_Of_Rows_Output 2 Percentage_Of_Rows_NotSelected_By_Primary_Filter 71.66655821 Percentage_Of_Primary_Filter_Rows_Selected_By_Internal_Filter 0 Internal_Filter_Efficiency 0 Primary_Filter_Efficiency 0.003281055

「Base_Table_Rows 215138」はあまり意味がありません。テーブルには215,000ではなく107,000行があります

レンダリングすると、データセットは次のようになります: (ソース: norman.cx )代替テキスト

さらなる研究:

このデータを使用したプライマリ フィルターのパフォーマンスの悪さに、私は引き続き戸惑っています。そこで、データがどのように分割されるかを正確に確認するためのテストを行いました。元の分割されていない機能を使用して、テーブルに「セル」列を追加しました。次に、16 のクエリを実行して、フィーチャが 4x4 グリッド内でいくつのセルにまたがっているかをカウントしました。そこで、各セルに対して次のようなクエリを実行しました。

declare  @box1 geometry = geometry::STGeomFromText('POLYGON ((
-180 90,
-90 90,
-90 45,
-180 45,
-180 90))', 4326)
update ContA set cells = cells + 1 where
geom.STIntersects(@box1) = 1

次に、表の「セル」列を見ると、データ セット全体で、4x4 グリッド内の複数のセルと交差するフィーチャは 672 個しかありません。では、まったく文字通り、幅 200 マイルの小さな四角形を参照するクエリに対して、プライマリ フィルターが 60,000 個のフィーチャを返すことができるでしょうか。

この時点で、これらの機能に対する SQL Server のパフォーマンスよりも優れた独自のインデックス作成スキームを作成できるようです。

4

3 に答える 3

12

インデックス クエリでは、次を使用します。

CREATE SPATIAL INDEX [contasplit_sidx] ON [dbo].[ContASplit] 
(
    [geom]
)USING  GEOMETRY_GRID 
WITH (
BOUNDING_BOX =(-90, -180, 90, 180),
...

したがって、BOUNDING_BOX は次のようにマップされます。

xmin = -90
ymin = -180
xmax = 90
ymax = 180
  • 経度 (-180 ~ 180 - 子午線の東/西を指定) は X にマップする必要があります
  • 緯度 (-90 ~ 90 - 赤道の北または南の距離を指定) が Y にマッピングされる必要があります

したがって、世界の BOUNDING_BOX を作成するには、次を使用する必要があります。

CREATE SPATIAL INDEX [contasplit_sidx] ON [dbo].[ContASplit] 
(
    [geom]
)USING  GEOMETRY_GRID 
WITH (
BOUNDING_BOX =(-180, -90, 180, 90),
...

これにより、データに適合するインデックスが作成され、すべての機能がインデックスによってカバーされます。

于 2010-06-07T10:21:15.113 に答える
5

データの分割

クエリがデータを表示するためのものである場合は、グリッドを使用して大きなポリゴンを分割できます。これらは、インデックスを使用して非常にすばやく取得できます。アウトラインを削除して、機能が引き続き連続しているように見せることができます。

ほとんどの商用GISパッケージには、あるポリゴンデータセットを別のポリゴンデータセットに分割するためのツールが含まれています。交差点を実行するツールを検索します。

OpenSourceを使用している場合は、QGISとhttp://www.ftools.caを参照してください。これらは、「交差、差分、結合、ディゾルブ、クリッピングなどのジオプロセシング操作を実行します」。私は後者を自分で使用していません。

大きな機能が悪い理由については、 http ://postgis.refractions.net/docs/ch04.html#id2790790をご覧ください。

フィルターと交差

フィルタ句の詳細については、こちらをご覧ください-http://blogs.msdn.com/b/isaac/archive/2010/03/04/filter-one-odd-duck.aspx

空間インデックス

他に確認する必要があるのは、空間インデックスがクエリプランで実際に使用されていることです。WITH句でインデックスを使用するようにクエリを強制する必要がある場合があります。

http://blogs.msdn.com/b/isaac/archive/2008/08/29/is-my-spatial-index-being-used.aspx

以下のインデックスの詳細:

http://blogs.msdn.com/b/isaac/archive/2009/05/28/sql-server-spatial-indexing.aspx

また、データに対してsp_help_spatial_geometry_indexを実行して、空間インデックスに使用する設定を確認してください。

http://msdn.microsoft.com/en-us/library/cc627426.aspx

このSPをいくつかのテストジオメトリで実行すると、データに合わせてインデックスを調整するためのあらゆる種類の統計が生成されます。プロパティの完全なリストは、http://msdn.microsoft.com/en-us/library/cc627425.aspxにあります。

これらには、次のような値が含まれます。

  • CellArea_To_BoundingBoxArea_Percentage_In_Level1
  • Number_Of_Rows_Selected_By_Primary_Filter

混乱したジオメトリ

sp_help_spatial_geometry_indexの結果から、空間インデックスではなくジオメトリ自体に問題があるようです。

Base_Table_Rowsカウントはバグのようです-http: //connect.microsoft.com/SQLServer/feedback/details/475838/number-of-rows-in-base-table-incorrect-in-sp-help-spatial-geography -index-xml テーブル/データベースを再作成し、インデックスを最初から試す価値があるかもしれません。

Total_Number_Of_ObjectCells_In_Level0_In_Index 60956は、レベル0で返される多くの機能です。これらは、空間インデックスの範囲外にあるか、nullである可能性があります。次に、これらすべての機能でIntersect(Number_Of_Times_Secondary_Filter_Is_Called 60956)を実行します。これにより、速度が低下する理由が説明されます。ドキュメントはnull機能のパフォーマンスへの影響はないと主張していますが、交差が実行されていない場合でも、レコードを検索する必要があると思います。

NULLおよび空のインスタンスはレベル0でカウントされますが、パフォーマンスには影響しません。レベル0には、ベーステーブルにNULLおよび空のインスタンスと同じ数のセルがあります。

Primary_Filter_Efficiency 0.003281055は、0.03%の効率を示していると思います。

試すべきいくつかのこと:

  1. SELECT * FROM sys.spatial_indexesから何か奇妙なことはありますか?
  2. MakeValidステートメント:

    UPDATE MyTable SET GeomFieldName = GeomFieldName.MakeValid()

  3. SRIDをリセット/再確認します。

    MyTable SET GeomFieldName.STSrid=4326を更新します

  4. いくつかのフィールドに追加して、機能の範囲を表示します。これにより、問題/NULLジオメトリが強調される場合があります。

    ALTER TABLE MyTable ADD MinX AS(CONVERT(int、GeomFieldName.STEnvelope()。STPointN((1))。STX、0))PERSISTED ALTER TABLE MyTable ADD MinY AS(CONVERT(int、GeomFieldName.STEnvelope()。STPointN(( 1))。STY、0))PERSISTED ALTER TABLE MyTable ADD MaxX AS(CONVERT(int、GeomFieldName.STEnvelope()。STPointN((3))。STX、0))PERSISTED ALTER TABLE MyTable ADD MaxY AS(CONVERT(int 、GeomFieldName.STEnvelope()。STPointN((3))。STY、0))PERSISTED

于 2010-05-30T19:17:36.567 に答える
0

私も、ジオメトリの特定のテーブルに適切な空間インデックスが何であるかを「推測」するのが非常に難しいことに気づきました。sp_help_spatial_geometry_index ストアド プロシージャを使用して、より知識に基づいた推測を試みました。これは、「GUESS」のたびに空間インデックスのパフォーマンスがどれほど悪いかを教えてくれただけです。2〜8個のCELLS_PER_OBJECTだけを考えて選択肢を限定したとしても、それだけで567 の順列が得られます (3 つのタイプを 4 回選択 = 81。その後、CELLS_PER_OBJECT オプションを 7 倍します)。私は、SQL サーバーに実験を任せて、経験的な証拠を得ることにしました。私はストアド プロシージャを作成しました。このストアド プロシージャは、順列をスピンし、順列ごとに空間テーブルの空間インデックスを再構築します。次に、提供された 2 つのジオメトリ インスタンスを使用して、空間インデックスの各順列のクエリ パフォーマンスをテストします。データ セット全体を含む 1 つのジオメトリ インスタンスを選択してから、データ セットの一部を含む別のインスタンスを選択しました。このプロシージャは、各インスタンスで STIntersect() を 4 回使用し、結果をテーブルに記録します。その後、結果テーブルにクエリを実行して、特定のデータ セットで最もパフォーマンスの高い空間インデックスを見つけることができます。

このhttps://gist.github.com/anonymous/5322650を使用して proc を作成します。次に、次の例を使用して実行ステートメントを設定します。

/* set up some strings to be used to create geometry instances when our test spatial queries run */ 
DECLARE @ada VARCHAR(MAX) 
SET @ada = 'GEOMETRY::STGeomFromText(''POLYGON ((2422068 527322, 2422068 781170, 2565405 781170, 2565405 527322, 2422068 527322))'', 0)'
DECLARE @mer VARCHAR(MAX) 
SET @mer = 'GEOMETRY::STGeomFromText(''POLYGON ((2451235 696087, 2451235 721632, 2473697 721632, 2473697 696087, 2451235 696087))'', 0)'
DECLARE @mer1 VARCHAR(MAX) 
SET @mer1 = 'GEOMETRY::STGeomFromText(''POLYGON ((244386 712283, 2443866 717980, 2454872 717980, 2454872 712283, 244386 712283))'', 0)'
DECLARE @mer2 VARCHAR(MAX) 
SET @mer2 = 'GEOMETRY::STGeomFromText(''POLYGON ((2434259 687278, 2434259 701994, 2449657 701994, 2449657 687278, 2434259 687278))'', 0)'


EXEC gis.sp_tune_spatial_index 'PARCEL_ADA', 'S104_idx', 2, 8, @ada, @mer1 
GO

注: 明らかに、空間インデックスを 567 回再構築するには長い時間がかかります。コマンドラインから起動するか、他のことをしている間に実行させます。頻繁に使用するデータセットであり、ジオメトリが類似している場合は、proc を実行するのに時間をかけるだけの価値があります。結果表には、パフォーマンスがミリ秒単位で表示されます。

于 2013-04-05T20:13:43.903 に答える