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

时间:2010-08-12 17:00:35

标签: sql-server sql-server-2008 geospatial spatial-index

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

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

DECLARE @Shape GEOMETRY = ...
SELECT * FROM PointsTable WHERE Point.STWithin(@Shape) = 1

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

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

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

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

编辑: 我也在a Microsoft forum上发布了这个帖子。以下是他们在那里要求的一些信息:

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

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
  )

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

对于这些测试,我运行了一个测试搜索(我的原始帖子中列出的那个),每个索引都有一个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.

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

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

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

8 个答案:

答案 0 :(得分:3)

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

显然,如果计划员在解析时不知道实际的几何图形,那么他很难建立一个好的计划。 autor建议插入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

使用:

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

答案 1 :(得分:3)

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

对于多边形表上的空间索引,

解决方案如下:

  1. 使用“几何自动网格”而不是旧的MMLL等。这提供了8级索引而不是旧的4级,并且设置是自动的。 AND ...
  2. 将'每个对象的单元格'设置为2000或4000.(考虑到默认值为16,这不容易猜到!)
  3. 这产生了巨大的变化。它比默认配置中的空间索引快10倍,并且比没有索引快60倍。

答案 2 :(得分:2)

我相信STIntersects更好地优化使用索引会比STWithin具有更好的性能,特别是对于更大的形状。

答案 3 :(得分:1)

我的直觉反应是“因为微软并没有费心去做,因为它不是企业特色”。也许我是愤世嫉俗的。

我不确定你为什么要离开Postgres。

答案 4 :(得分:1)

您是否正确设置了空间索引?你的边界框是否正确?里面的所有点都是?在你的情况下,GRID的HHMM可能效果最好(再次取决于一个装箱)。

您可以尝试使用sp_help_spatial_geometry_index,看看有什么问题吗? http://msdn.microsoft.com/en-us/library/cc627426.aspx

请尝试使用过滤操作,并告诉我们您获得的穿孔数量是多少? (它只执行主过滤器(使用索引)而不经过二级过滤器(真正的空间操作))

您的设置出了问题。空间确实是新功能,但它并没有那么糟糕。

答案 5 :(得分:1)

您可以尝试将其分为两遍:

  1. 将候选人选入临时表w / .Filter()
  2. 查询候选人w / .STWithin()
  3. 例如:

    SELECT * INTO #this FROM PointsTable WHERE Point.Filter(@Shape) = 1
    SELECT * FROM #this WHERE Point.STWithin(@Shape) = 1
    

    (仅使用减少I / O所需的实际列替换SELECT *

    这种微优化不应该是必要的,但我之前已经看到了不错的性能改进。此外,您将能够通过(1)到(2)的比率来衡量您的指数的选择性。

答案 6 :(得分:1)

执行效率问题除了SQL服务器使用Quadtree index,而PostGIS使用R-tree索引。

对于大多数情况,R-tree是更好的算法,特别是对于具有不同几何尺寸的大型数据集。

答案 7 :(得分:0)

我不熟悉空间查询,但它可能是参数化查询问题

尝试使用固定值编写查询(不使用参数)(使用对参数化查询执行速度较慢的值)并运行它。将时间与参数化版本进行比较。如果它快得多,那么你的问题就是参数化查询。

如果上面的速度要快得多,那么我会用字符串中嵌入的参数值动态构建你的sql字符串,这样你就可以删除引起问题的参数。