7

我有(我认为)是一个简单的 Sql Server 空间查询:

抓取存在于某个 4 边多边形内的所有美国州(即网页的 google/bing 地图的视口/边界框)

SELECT CAST(2 AS TINYINT) AS LocationType, a.Name AS FullName, 
    StateId, a.Name, Boundary.STAsText() AS Boundary, 
    CentrePoint.STAsText() AS CentrePoint
FROM [dbo].[States] a
WHERE @BoundingBox.STIntersects(a.Boundary) = 1

运行需要 6 秒 :(

这是执行计划....

已移除

过滤器操作的统计数据...

已移除

现在,我只是不知道如何调试这个 .. 找出我需要微调的内容等。我有任何空间索引吗?我相信是这样 ...

/****** Object:  Index [SPATIAL_States_Boundary]    
        Script Date: 07/28/2010 18:03:17 ******/
CREATE SPATIAL INDEX [SPATIAL_States_Boundary] ON [dbo].[States] 
(
    [Boundary]
)USING  GEOGRAPHY_GRID 
WITH (
    GRIDS =(LEVEL_1 = HIGH,LEVEL_2 = HIGH,LEVEL_3 = HIGH,LEVEL_4 = HIGH), 
    CELLS_PER_OBJECT = 1024, PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, 
    DROP_EXISTING = OFF, ALLOW_ROW_LOCKS  = ON, 
    ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

我是否需要提供有关GEOGRAPHY返回数据的更多信息?例如。点数等?还是我需要运行profiler并从那里提供一些统计数据?

还是我的 Cells_per_object / Grids 设置不正确(我真的不知道应该将这些值设置为什么,TBH)。

有人可以帮忙吗?请?

更新/编辑:

在下面@Bobs 的第一次回复确认空间索引没有被使用后,因为主键(聚集索引)将比具有 50 奇数行的表上的非聚集索引更快......然后我试图强制空间索引(对于shits-n-giggles):-

SELECT CAST(2 AS TINYINT) AS LocationType, a.Name AS FullName, 
    StateId, a.Name, Boundary.STAsText() AS Boundary, 
    CentrePoint.STAsText() AS CentrePoint
FROM [dbo].[States] a WITH (INDEX(SPATIAL_States_Boundary))
WHERE @BoundingBox.STIntersects(a.Boundary) = 1

...猜猜是什么..查询立即运行。

怎么回事?其他人知道为什么吗?我是否需要为此发布一个查询计划,以帮助解释为什么/什么?

4

2 回答 2

7

您似乎有一个运行查询的最佳计划。这将很难改进。以下是一些观察。

该查询正在对 PK_States 索引执行聚集索引扫描。它没有使用空间索引。这是因为查询优化器认为使用聚集索引而不是任何其他索引会更好。为什么?可能是因为 States 表中的行数很少(华盛顿特区、波多黎各等地可能还有 50 行加上其他行)。

SQL Server 在 8KB 页上存储和检索数据。过滤操作的行大小(请参阅 Estimate Row Size)为 8052 字节,这意味着每页有一行,整个表大约有 50 页。查询计划估计它将处理其中大约 18 行(请参阅估计的行数)。这不是要处理的大量行。我的解释没有解决表格中的额外页面,但关键是这个数字大约是 50 页,而不是 50,000 页。

所以,回到为什么它使用 PK_States 索引而不是 SPATIAL_States_Boundry 索引。根据定义,聚集索引包含表的实际数据。非聚集索引指向数据所在的页面,因此需要检索的页面更多。因此,非聚集索引只有在数据量较大时才有用。

您可以做一些事情来减少页面进程的数量(例如,使用覆盖索引),但是您当前的查询已经很好地优化了,您不会看到太多的性能改进。

于 2010-07-28T21:11:43.063 回答
2

试试这个,没有索引提示:

EXEC sp_executesql N'
  SELECT CAST(2 AS TINYINT) AS LocationType, a.Name AS FullName, 
      StateId, a.Name, Boundary.STAsText() AS Boundary, 
      CentrePoint.STAsText() AS CentrePoint
  FROM [dbo].[States] a
  WHERE @BoundingBox.STIntersects(a.Boundary) = 1'
, N'@BoundingBox GEOGRAPHY', @BoundingBox

如果这有什么不同,请参阅此处了解更多详细信息:

如果您在 SSMS 中运行代码,请在空间查询周围使用 sp_executesql(或使用您自己的将空间值作为参数的存储过程)以确保查询成本器在创建查询计划时“知道”参数值,即在批处理开始时或进入存储过程或 sp_executesql 时。

于 2010-09-05T06:02:19.670 回答