选择具有大多边形的良好SQL Server 2008空间索引

and*_*ncx 12 spatial geospatial spatial-query sql-server-2008 spatial-index

我正在尝试为我正在处理的数据集选择一个不错的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
Run Code Online (Sandbox Code Playgroud)

这是查询与表中只有两个多边形相交的区域.无论我选择何种空间索引设置组合,Filter()总是返回大约60,000行.

用STIntersects()替换Filter()当然只返回我想要的两个多边形,但当然需要更长的时间(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)
Run Code Online (Sandbox Code Playgroud)

然后我使用每个边界框来选择和截断与该框相交的多边形:

insert ContASplit
select CODE, geom.STIntersection(@box1), CODE_DESC from ContA
where geom.STIntersects(@box1) = 1
Run Code Online (Sandbox Code Playgroud)

我显然为4x4网格中的所有16个边界框做了这个.最终结果是我有一个新表~107,000行(这证实我实际上没有很多巨大的多边形).

我添加了一个空间索引,每个对象有1024个单元格,每个级别的单元格低,低,低,低.

然而,非常奇怪的是,这个具有分割多边形的新表仍然与旧表一样.执行上面列出的.Filter 仍然会返回~60,000行.我根本不理解这一点,显然我不明白空间索引实际上是如何工作的.

矛盾的是,虽然.Filter()仍然返回~60,000行,但它的性能有所提高..Filter()现在大约需要2秒而不是6秒,而.STIntersects()现在需要6秒而不是12秒.

这里要求的是索引的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]
Run Code Online (Sandbox Code Playgroud)

虽然记得,我已经为每个对象的网格和单元格尝试了一系列不同的设置,每次都有相同的结果.

以下是运行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 5.625 Height_Of_Cell_In_Level1 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"对我来说没什么意义,表中有107,000行,而不是215,000行

渲染时,数据集如下所示: alt text http://norman.cx/photos/links/wms.png

进一步的研究:

我仍然对这个数据的主过滤器性能不佳感到困惑.所以我做了一个测试,看看我的数据究竟是如何分裂的.使用我原来的非分裂功能,我在表格中添加了一个"单元格"列.然后我运行了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
Run Code Online (Sandbox Code Playgroud)

如果我然后查看表格中的"单元格"列,则整个数据集中只有672个要素与4x4网格中的多个单元格相交.那么在地球上,从字面上看,主滤波器能够为查看200英里宽的小矩形的查询返回60,000个特征吗?

在这一点上,我似乎可以编写自己的索引方案,该方案可以更好地运行SQL Server对这些功能的执行情况.

geo*_*ika 12

在索引查询中,您使用:

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

因此BOUNDING_BOX映射到:

xmin = -90
ymin = -180
xmax = 90
ymax = 180
Run Code Online (Sandbox Code Playgroud)
  • Longlyitude(-180到180 - 指定Meridian的东/西)应该映射到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),
...
Run Code Online (Sandbox Code Playgroud)

这应创建一个适合您的数据的索引,并表示索引涵盖了您的所有功能.


geo*_*ika 5

拆分数据

如果查询用于显示数据,则可以使用网格分割大型多边形.然后可以使用索引快速检索这些内容.您可以删除轮廓,以便功能看起来仍然是连续的.

大多数商业GIS软件包都有工具将一个多边形数据集拆分成另一个.搜索执行交叉的工具.

如果您正在使用OpenSource,那么请查看QGIS和http://www.ftools.ca,它们"执行地理处理操作,包括交叉,差异,联合,溶解和剪切".我自己没有用过后者.

看看:http://postgis.refractions.net/docs/ch04.html#id2790790,了解为什么大功能不好.

过滤和相交

Filter命令中有更多内容 - 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返回的许多功能.很可能它们要么在空间索引范围之外,要么为空.然后它会在所有这些功能上运行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声明:

    更新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