STIntersectsのパフォーマンスの向上


11

テーブルにT_PINは300,000のピンとT_POLYGON36,000のポリゴンがあります。T_PINこのインデックスがあります:

CREATE SPATIAL INDEX [T_PIN_COORD] ON [dbo].[T_PIN]
(
[Coord]
)USING  GEOGRAPHY_GRID 
WITH (GRIDS =(LEVEL_1 = HIGH,LEVEL_2 = HIGH,LEVEL_3 = HIGH,LEVEL_4 = HIGH), 
CELLS_PER_OBJECT = 128, PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, 
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY];

T_POLYGON 持っています:

CREATE SPATIAL INDEX [T_POLYGON_COORD] ON [dbo].[T_POLYGON]
(
[COORD]
)USING  GEOGRAPHY_GRID 
WITH (GRIDS =(LEVEL_1 = HIGH,LEVEL_2 = HIGH,LEVEL_3 = HIGH,LEVEL_4 = HIGH), 
CELLS_PER_OBJECT = 128, PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, 
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) 
ON [PRIMARY];

の交差を検索するクエリでT_PINT_POLYGON実行に45分以上かかります。

SELECT COUNT(*)
FROM T_PIN 
INNER JOIN T_POLYGON
    ON T_PIN.Coord.STIntersects(T_POLYGON.COORD) = 1;

結果は4,438,318行です。

このクエリを高速化するにはどうすればよいですか?


「T_POLYGON.Coord.STIntersects(T_PIN.COORD)= 1」を使用してみましたか?
トラビス2014年

クエリプランを確認してください。私はPostgresで作業しますが、同様のクエリを実行する必要がありますが、非常に大きなデータセットで実行します。私は最悪のものを約2日間(残念ながらスクリプトを含む)まで減らす手法を考え出しましたが、まずクエリプランを確認したいと思います。
John Powell

2つのテーブルのポリゴンを掛け合わせると、潜在的な交差の数の点で、組み合わせの数よりも7000倍多い数があるので、この2日間はかなり良さそうだと思います。ただし、クエリプランを確認せず、ポリゴンあたりの平均ポイント数を把握していないと、具体的な解決策を見つけるのは困難です。
John Powell

回答:


7

まず、クエリ実行プランを調べて空間インデックスが使用されているかどうかを確認し、クラスター化インデックスシーク(空間)アイテムがあるかどうかを確認します。

それが使用されていると仮定すると、最初に確認するために、単純化されたポリゴンを含むバウンディングボックスに基づいてセカンダリ/単純化されたフィルターを追加してみることができます。次に、これらの単純化されたポリゴンとの一致をプライマリフィルターで実行して、最終的な結果を得ることができます。

1)[dbo]。[T_POLYGON]テーブルに新しいgeographyとgeometry列を追加します。

ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeom geometry;
ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog geography;

2)バウンディングボックスポリゴンを作成します(これには、STEnvelope()を利用するためのジオメトリへの初期変換が含まれます)。

UPDATE [dbo].[T_POLYGON] SET SimplePolysGeom = geometry::STGeomFromWKB(
    COORD.STAsBinary(), COORD.STSrid).STEnvelope();

UPDATE [dbo].[T_POLYGON] SET SimplePolysGeog = geography::STGeomFromWKB(
    SimplePolysGeom.STAsBinary(), SimplePolysGeom.STSrid);

3)簡略化されたgeography列に空間インデックスを作成する

4)この単純化されたgeography列に対する交差を取得し、一致するgeographyデータ型で再度フィルター処理します。おおよそ、次のようなもの:

;WITH cte AS
(
   SELECT pinID, polygonID FROM T_PIN INNER JOIN T_POLYGON
    ON T_PIN.Coord.STIntersects(T_POLYGON.SimplePolysGeog ) = 1
)
SELECT COUNT(*)
FROM T_PIN 
INNER JOIN T_POLYGON
    ON T_PIN.Coord.STIntersects(T_POLYGON.COORD) = 1
    AND T_PIN.pinID IN (SELECT pinID FROM cte)
    AND T_POLYGON.polygonID IN (SELECT polygonID FROM cte)

編集:(1)と(2)をこの計算された永続的な列に置き換えることができます。提案のためのポールホワイトへの信用。

ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog AS  ([geography]::STGeomFromWKB([geometry]::STGeomFromWKB([COORD].[STAsBinary](),[COORD].[STSrid]).STEnvelope().STAsBinary(),(4326))) PERSISTED

ええ、それは多かれ少なかれ私が得ていたものです。広いカバレッジエリアで2つのテーブルセットを空間的に「結合」するときに私が見つけた問題は、オプティマイザが2つのフルテーブルスキャンとポリゴンテストのポイントのロードを頻繁に行うことです。
John Powell

2

このようなクエリは、ポリゴンが複雑なために、時間がかかることがよくあります。(たとえば)複雑な海岸線が境界近くのポイントをテストするために年齢を取り、ポイントが内側か外側かを見つけるために多くのレベルをズームする必要があることを見てきました。

...それで.Reduce()、ポリゴンを試してみて、それが役立つかどうかを確認できます。

その関数の詳細については、http://msdn.microsoft.com/en-us/library/cc627410.aspxを参照してください


1

Microsoftのドキュメントによると、空間インデックスは、WHERE句を含む比較述語の先頭にある場合、次のメソッドの地理タイプで使用されます。

  • STIntersects
  • STDistance
  • STEquals

でジオメトリタイプのメソッド(制限付きリスト)のみが空間インデックスの使用をトリガーするJOIN ... ONため、使用するコードを変更するWHERE geog1.STIntersects(geog2) = 1と、速度が向上します。

また、g2serverの回答でアドバイスを受け、フィルタリングと空間インデックスを追加するために以下を追加することをお勧めします

ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog AS
     ([geography]::STGeomFromWKB([geometry]::STGeomFromWKB([COORD].[STAsBinary](),
                                                           [COORD].[STSrid])
                 .STEnvelope().STAsBinary(),(4326))) PERSISTED

次に、次のようなクエリを作成します(この投稿はすぐに作成し、まだテストしていません。クエリと投稿された最高の回答でJOIN ON空間演算= 1を使用し、空間インデックス):

SELECT   
     (SELECT p2.polygon_id
      FROM   T_Polygon p2
      WHERE  p2.coords.STIntersects(t.coords) = 1),
     t.pin_id
FROM     T_PIN t
WHERE    
     (SELECT t.coords.STIntersects(p.coords)
      FROM   T_POLYGON p
      WHERE  t.coords.STIntersects(p.SimplePolysGeog) = 1) = 1

参考:上記は、SimplePolysGeog最終的にオーバーラップする場合は機能しません(ピンが2つの簡略化されたジオグにある可能性があります。これは、州内の境内の人々に対してこれを実行しただけで、通常のポリゴンは境界を共有するため、境界ボックスがオーバーラップします)。したがって、ほとんどの場合場合によっては、サブクエリが複数の結果を返すというエラーがスローされます。

MS Docsの空間インデックスの概要から

空間インデックスでサポートされる地理的方法

特定の条件下で、空間インデックスは次のセット指向の地理メソッドをサポートします:STIntersects()、STEquals()、およびSTDistance()。空間インデックスでサポートするには、これらのメソッドをクエリのWHERE句内で使用する必要があり、これらのメソッドは次の一般的な形式の述語内で発生する必要があります。

geography1.method_name(geography2)comparison_operatorvalid_number

null以外の結果を返すには、geography1geography2に同じ空間参照識別子(SRID)が必要です。それ以外の場合、メソッドはNULLを返します。

空間インデックスは、次の述語形式をサポートしています。


空間インデックスを使用するクエリ

空間インデックスは、WHERE句にインデックス付きの空間演算子を含むクエリでのみサポートされます。たとえば、次のような構文:

[spatial object].SpatialMethod([reference spatial object]) [ = | < ] [const literal or variable]

クエリオプティマイザーは、空間演算(その@a.STIntersects(@b) = @b.STInterestcs(@a))の交換可能性を理解します。ただし、比較の開始に空間演算子が含まれていない場合(たとえばWHERE 1 = spatial op、空間インデックスを使用しない場合)、空間インデックスは使用されません。空間インデックスを使用するには、比較を書き換えます(例:)WHERE spatial op = 1

...

次のクエリは、SimplePolysGeogs重複している場合に機能します。

;WITH cte AS
(
   SELECT T_PIN.PIN_ID, 
          T_POLYGON.POLYGON_ID, 
          T_POLYGON.COORD 
   FROM T_PIN 
   INNER JOIN T_POLYGON
   ON T_PIN.COORD.STIntersects(T_POLYGON.SimplePolysGeog) = 1
)

SELECT COUNT(*)
FROM T_PIN 
INNER JOIN cte
ON T_PIN_PIN_ID = cte.PIN_ID
where cte.[COORD].STIntersects(T_PIN.COORD) = 1
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.