我正在尝试为我正在处理的数据集选择一个体面的 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 对这些功能的执行方式更好。