【问题标题】:Why are my spatial searches slower in SQL Server than PostGIS?为什么我在 SQL Server 中的空间搜索比 PostGIS 慢?
【发布时间】:2011-03-29 01:29:12
【问题描述】:

我正在努力将一些空间搜索功能从带有 PostGIS 的 Postgres 转移到 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,还不错,但仍然也不擅长)。

我能够得到使用的索引,只是没有帮助。每个测试都是在打开“显示实际执行计划”的情况下运行的,它总是显示索引。

【问题讨论】:

  • +1:我也想知道。
  • 您的百万点数据是存储为几何(平面、欧几里得空间)还是地理(圆形、土形坐标)?如果您正在混合几何和地理,您将引入转换数学的性能影响。
  • @Mwalker,都是几何图形,我不认为你可以混合和匹配它们。
  • 感谢您对 CELLS_PER_OBJECT 的评论。我使用 CELLS_PER_OBJECT = 16 和级别 = MEDIUM 获得了 6.8 秒,我将 CELLS_PER_OBJECT 更改为 256 和级别 = HIGH,时间下降到 2.8 秒 :-)

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


【解决方案1】:

除了 SQL 服务器使用 Quadtree index 而 PostGIS 使用 R-tree 索引之外的实施效率问题。

在大多数情况下,R-tree 是更好的算法,尤其是对于具有不同几何大小的大型数据集。

【讨论】:

    【解决方案2】:

    我刚刚花了一天时间解决一个类似的问题。特别是,我们正在做一个多边形内点类型的查询,其中有一组相对较小的多边形,但每个多边形都很大而且很复杂。

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

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

    这有很大的不同。它比默认配置中的空间索引快 10 倍,比完全没有索引快 60 倍。

    【讨论】:

      【解决方案3】:

      你可以试着把它分成两遍:

      1. 使用.Filter() 将候选人选择到临时表中。
      2. 使用.STWithin()查询候选人。

      例如:

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

      (仅将 SELECT * 替换为您需要减少 I/O 的实际列)

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

      【讨论】:

        【解决方案4】:

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

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

        尝试改用过滤器操作并告诉我们您得到的性能数字是多少? (它只执行初级过滤器(使用索引)而不经过二级过滤器(真正的空间操作))

        您的设置有问题。空间确实是新功能,但还不错。

        【讨论】:

        • 我已经尝试了两种尺寸(LLLL、LLMM、LLHH、MMLL 等)的所有组合,最好的是 MMMM,每个对象有 256 个单元格。 sp_help_spatial_geometry_index 说初级过滤器的效率为 90%,我认为这可能是问题所在(其他过滤器效率低至 70%)。 FilterSTIntersects 快​​得多,但仍然比 Postgres 慢 2-5 倍(而且不准确)。
        • 我们认为问题在于我们的数据在高密度区域中相当稀疏,因此静态网格大小方法没有帮助。如果将网格设置为高,则索引在稀疏区域过于具体,但如果将其设置为低,则索引在高密度区域无用。
        • 然后尝试在每个高密度区域周围设置多个空间索引。或者至少将整个美国分成几个大区域。我希望您的大部分数据都在东海岸和西海岸。
        • 我们的数据不是整个美国,而是科罗拉多州。问题是用户可以选择跨越整个州的区域。例如,我的测试查询是从 Fort Collins 到 Denver 的一个小盒子。这有两个高密度区域被一个低密度区域隔开,我的印象是 SQL Server 一次只会使用一个空间索引(不索引这两个区域之一会比我现在更糟糕) .
        • 我可以尝试在星期一再次加载这个数据库来再次测试它,目前我们刚刚删除它,因为这种配置比使用两个数据库要复杂得多。
        【解决方案5】:

        我相信 STIntersects 对于使用索引进行了更好的优化,比 STWithin 具有更好的性能,尤其是对于较大的形状。

        【讨论】:

        • STIntersects 查询设置统计配置文件后,您是否可以发布计划信息?
        【解决方案6】:

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

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

        如果上面的速度更快,那么我会动态构建你的 sql 字符串,并将参数值嵌入到字符串中,这样你就可以删除导致问题的参数。

        【讨论】:

        • 这里的问题似乎不太可能是查询参数化。 OP 说:“如果我选择一个相当小的形状,有时我可以得到亚秒级的时间,但如果我的形状相当大(有时是这样),我可以得到超过 5 分钟的时间。” i> 1. 查询性能似乎受到查询几何的空间属性的影响。 2. 即使您认为参数化查询可能很慢,它们也不应该将快速查询变成需要超过 5 分钟 (!) 才能执行的查询...我想不出任何合理的解释为什么他们会产生这种效果。
        【解决方案7】:

        我的直觉反应是“因为微软没有费心让它快速,因为它不是企业功能”。可能是我玩世不恭。

        我也不确定你为什么要从 Postgres 迁移出去。

        【讨论】:

        • 我怀疑这与它是一个新功能有关;我听说他们应该在下一个版本中让它变得更好。让我感到困惑的是,我没有听说过它很慢,所以我担心我只是错过了一些东西。
        • 在 SQL Server 中使用空间索引后,我开始意识到这是真的。
        【解决方案8】:

        以下是关于 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
        

        与:

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

        【讨论】:

        • 我的空间索引正在被使用。我点击“包括实际执行计划”,它显示了正在使用的空间索引。
        • 我尝试了这个建议只是为了确定时间和执行计划是一样的。
        猜你喜欢
        • 2020-09-17
        • 1970-01-01
        • 2014-12-12
        • 2015-09-23
        • 1970-01-01
        • 2011-05-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多