为什么SQL Server中的空间搜索速度比PostGIS慢?

Rei*_*ica 11 sql-server geospatial sql-server-2008 spatial-index

我正在努力将一些空间搜索功能从Postgres与PostGIS一起移动到SQL Server,我看到一些相当糟糕的性能,即使是索引也是如此.

我的数据大约有一百万个点,我想找出哪些点在给定的形状内,所以查询看起来像这样:

DECLARE @Shape GEOMETRY = ...
SELECT * FROM PointsTable WHERE Point.STWithin(@Shape) = 1
Run Code Online (Sandbox Code Playgroud)

如果我选择一个相当小的形状,我有时可以得到亚秒,但如果我的形状相当大(有时它们),我可以得到超过5分钟的时间.如果我在Postgres中运行相同的搜索,它们总是在一秒钟之内(事实上,几乎所有搜索都在200毫秒之内).

我在我的索引上尝试了几种不同的网格大小(全高,全中,全低),每个对象不同的单元格(16,64,256),无论我做什么,时间都保持不变.我想尝试更多组合,但我甚至不知道要走哪条路.每个对象更多的细胞?减?一些奇怪的网格尺寸组合?

我查看了我的查询计划,他们总是使用索引,它根本就没有帮助.我甚至试过没有索引,并没有更糟糕.

有没有人可以给出任何建议?我能找到的一切都表明"我们不能给你任何关于索引的建议,只是尝试一切,也许一个会工作",但是用10分钟创建一个索引,盲目地做这个是浪费大量时间.

编辑:我也在微软论坛上发布了这个.以下是他们在那里要求的一些信息:

我能得到的最好的工作指数就是这个:

CREATE SPATIAL INDEX MapTesting_Location_Medium_Medium_Medium_Medium_16_NDX
    ON MapTesting (Location)
 USING GEOMETRY_GRID
  WITH (
    BOUNDING_BOX = ( -- The extent of our data, data is clustered in cities, but this is about as small as the index can be without missing thousands of points
        XMIN = -12135832,
        YMIN = 4433884,
        XMAX = -11296439,
        YMAX = 5443645),
    GRIDS = (
        LEVEL_1 = MEDIUM,
        LEVEL_2 = MEDIUM,
        LEVEL_3 = MEDIUM,
        LEVEL_4 = MEDIUM),
     CELLS_PER_OBJECT = 256 -- This was set to 16 but it was much slower
  )
Run Code Online (Sandbox Code Playgroud)

我在使用索引时遇到了一些问题,但这是不同的.

对于这些测试,我运行了一个测试搜索(我的原始帖子中列出的那个),每个索引都有一个WITH(INDEX(...))子句(测试网格大小和每个对象的单元格的各种设置),一个没有任何提示.我还使用每个索引和相同的搜索形状运行sp_help_spatial_geometry_index.上面列出的索引运行得最快,并且在sp_help_spatial_geometry_index中也列为最有效.

运行搜索时,我得到以下统计信息:

(1 row(s) affected)
Table 'MapTesting'. Scan count 0, logical reads 361142, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'extended_index_592590491_384009'. Scan count 1827, logical reads 8041, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 6735 ms,  elapsed time = 13499 ms.
Run Code Online (Sandbox Code Playgroud)

我也尝试使用随机点作为数据(因为我无法给出我们的实际数据),但事实证明这种搜索对于随机数据来说非常快.这使我们相信我们的问题是网格系统如何与我们的数据一起工作.

我们的数据是整个州的地址,因此有一些非常高密度的区域,但主要是稀疏数据.我认为问题是没有任何网格尺寸设置适用于两者.当网格设置为HIGH,索引在低密度区域返回太多单元格,并且网格设置为LOW,网格在高密度区域中无用(在MEDIUM,它不是那么糟糕,但仍然不擅长).

我能够获得使用的索引,它只是没有帮助.每个测试都在启用"显示实际执行计划"的情况下运行,并且始终显示索引.

Joh*_*SFT 5

我刚刚在类似的问题上度过了一天。特别是,我们正在做一个点入多边形类型的查询,其中有一组相对较小的多边形,但每个多边形都很大且很复杂。

对于多边形表上的空间索引,解决方案如下:

  1. 使用“几何自动网格”代替旧的 MMLL 等。这提供了 8 级索引而不是旧的 4 级,并且设置是自动的。和...
  2. 将 'cells per object' 设置为 2000 或 4000。(不容易猜到,因为默认值为 16!)

这产生了巨大的差异。它比默认配置中的空间索引快 10 倍,比没有索引快 60 倍。


Nor*_*ame 3

以下是关于 SQL-Server 空间扩展以及如何确保索引得到有效使用的一些说明:

显然,如果规划者在解析期间不知道实际的几何形状,则很难制定一个好的计划。作者建议插入exec sp_executesql

代替:

-- does not use the spatial index without a hint
declare @latlonPoint geometry = geometry::Parse('POINT (45.518066 -122.767464)')
select a.id, a.shape.STAsText() 
from zipcodes a 
where a.shape.STIntersects(@latlonPoint)=1
go
Run Code Online (Sandbox Code Playgroud)

和:

-- this does use the spatial index without using a hint
declare @latlonPoint geometry = geometry::Parse('POINT (45.518066 -122.767464)')
exec sp_executesql 
N'select a.id, a.shape.STAsText() 
from zipcodes a 
where a.shape.STIntersects(@latlonPoint)=1', N'@latlonPoint geometry', @latlonPoint
go
Run Code Online (Sandbox Code Playgroud)