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

这是查询与表中仅两个多边形相交的区域。无论我选择哪种空间索引设置组合,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)

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

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() 现在需要大约 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]

尽管请记住,我已经为每个对象的网格和单元格尝试了一系列不同的设置,每次都得到相同的结果。

以下是运行 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

渲染后的数据集如下所示:( 来源: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

如果我再查看表​​中的“单元格”列,我的整个数据集中只有 672 个特征与 4x4 网格中的超过 1 个单元格相交。那么,从字面上看,主过滤器如何返回 60,000 个特征来查看一个 200 英里宽的小矩形?

在这一点上,看起来我可以编写自己的索引方案,它会比 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 返回的要素。它们很可能在空间索引范围之外或为空。然后它在所有这些特征上运行 Intersect (Number_Of_Times_Secondary_Filter_Is_Called 60956),这可以解释为什么它很慢。即使文档声称空特征没有性能影响 - 我相信它仍然需要查找记录,即使没有执行相交。

NULL 和空实例计入级别 0,但不会影响性能。级别 0 将具有与基表中的 NULL 和空实例一样多的单元格。

我相信 0.003281055 的 Primary_Filter_Efficiency 表示效率为 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)) 持续

于 2010-05-30T19:17:36.567 回答
0

我也发现很难“猜测”特定几何表的适当空间索引是什么。我尝试使用 sp_help_spatial_geometry_index 存储过程进行更有根据的猜测。所有这一切都告诉我在每次“GUESS”之后我的空间索引的表现有多差。即使我通过仅考虑 2-8 个 CELLS_PER_OBJECT 来限制我的选择,仅此而已给出 567 个排列(3 种类型选择 4 次 = 81。然后乘以 7 个 CELLS_PER_OBJECT 选项)。我决定让 SQL Server 为我做实验并给我一些经验证据。我创建了一个存储过程,它将通过排列旋转并为每个排列重建空间表上的空间索引。然后它将使用两个提供的几何实例测试空间索引的每个排列的查询性能。我选择了一个包含整个数据集的几何实例,然后选择了另一个包含一小部分数据集的实例。proc 在每个实例上使用 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 回答