テーブルT_PIN
には300,000個のピンがあり、T_POLYGON
には36,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_PIN
とT_POLYGON
の共通部分を見つけるクエリは、実行に45分以上かかります。
SELECT COUNT(*)
FROM T_PIN
INNER JOIN T_POLYGON
ON T_PIN.Coord.STIntersects(T_POLYGON.COORD) = 1;
結果は4,438,318行です。
このクエリを高速化するにはどうすればよいですか?
まず、クエリ実行プランを調べて空間インデックスが使用されているかどうかを確認し、クラスター化インデックスシーク(空間)アイテムがあるかどうかを確認します。
それが使用されていると仮定すると、最初に確認するために、単純化されたポリゴンを含むバウンディングボックスに基づいてセカンダリ/単純化されたフィルターを追加してみることができます。これらの単純化されたポリゴンとの一致は、最終的な結果を得るためにプライマリフィルターを介して実行できます。
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)
[〜#〜] edit [〜#〜]:(1)と(2)をこの計算された永続列に置き換えることができます。提案のためのポールホワイトへの信用。
ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog AS ([geography]::STGeomFromWKB([geometry]::STGeomFromWKB([COORD].[STAsBinary](),[COORD].[STSrid]).STEnvelope().STAsBinary(),(4326))) PERSISTED
このようなクエリは、ポリゴンが複雑なため、時間がかかることがよくあります。 (たとえば)複雑な海岸線が境界近くのポイントをテストするのに年齢を要し、ポイントが内側か外側かを見つけるために多くのレベルをズームする必要があることを見てきました。
...それで、ポリゴンを.Reduce()
'してみて、それが役立つかどうかを確認できます。
その関数の詳細については、 http://msdn.Microsoft.com/en-us/library/cc627410.aspx を参照してください
Microsoftのドキュメントによると、空間インデックスは、WHERE
句のある比較述語の先頭にある場合、次のメソッドの地理タイプで使用されます。
STIntersects
STDistance
STEquals
ジオメトリタイプのメソッド(制限付きリスト)のみが_JOIN ... ON
_で空間インデックスの使用をトリガーするため、WHERE geog1.STIntersects(geog2) = 1
を使用するようにコードを変更すると、速度が向上します。
g2server's answer でアドバイスを受け、フィルタリングと空間インデックスを追加するために以下を追加することもお勧めします
_ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog AS
([geography]::STGeomFromWKB([geometry]::STGeomFromWKB([COORD].[STAsBinary](),
[COORD].[STSrid])
.STEnvelope().STAsBinary(),(4326))) PERSISTED
_
次に、次のようなクエリlikeを作成できます(私はこの投稿をすぐに書いて、まだテストしていません。これは、クエリと投稿された最高の回答は、空間インデックスを使用しないJOIN ON空間op = 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ドキュメントから 空間インデックスの概要 :
空間インデックスでサポートされる地理的方法
特定の条件下で、空間インデックスは次のセット指向の地理メソッドをサポートします:STIntersects()、STEquals()、およびSTDistance()。空間インデックスでサポートするには、これらのメソッドをクエリのWHERE句内で使用する必要があり、次の一般的な形式の述語内で実行する必要があります。
geography1.method_name(geography2)comparison_operatorvalid_number
Null以外の結果を返すには、geography1およびgeography2に同じ 空間参照識別子(SRID) 。それ以外の場合、メソッドはNULLを返します。
空間インデックスは、次の述語形式をサポートしています。
geography1。STIntersects(geography2)= 1
geography1。STEquals(geography2)= 1
geography1。STDistance(geography2)<number
geography1。STDistance(geography2)<=数値
空間インデックスを使用するクエリ
空間インデックスは、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
_