代码之家  ›  专栏  ›  技术社区  ›  Brendan Long

为什么我在SQL Server中的空间搜索比PostGIS慢?

  •  11
  • Brendan Long  · 技术社区  · 15 年前

    我正致力于将一些空间搜索功能从带有PostGIS的Postgres迁移到sqlserver,我看到了一些非常糟糕的性能,即使是使用索引。

    我的数据大约有一百万个点,我想找出这些点中的哪一个在给定的形状中,因此查询如下所示:

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

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

    我在索引上尝试了几种不同的网格大小(都是高、中、低),每个对象有不同的单元格(16、64、256),无论我做什么,时间都保持不变。我想尝试更多的组合,但我甚至不知道该往哪个方向走。每个对象有更多单元格?少一点?一些奇怪的网格大小组合?

    我也把这个贴在 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_索引。上面列出的索引运行速度最快,在sp_help_spatial_geometry_索引中也被列为效率最高的索引。

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

    (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 ,虽然没那么差,但还是不擅长)。

    我可以使用索引,但没用。每个测试都是在“show actual execution plan”打开的情况下运行的,它总是显示索引。

    8 回复  |  直到 15 年前
        1
  •  4
  •   John Rusk - MSFT    13 年前

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

    1. 使用“几何自动网格”而不是旧的MMLL等。这给出了8个级别的索引,而不是原来的4个级别,并且设置是自动的。还有。。。

    这造成了巨大的不同。它比默认配置中的空间索引快10倍,比完全没有索引的速度快60倍。

        2
  •  3
  •   Nordic Mainframe    15 年前

    以下是有关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
    
        3
  •  2
  •   Giri    15 年前

        4
  •  1
  •   tc.    15 年前

    我的直觉反应是“因为微软没有费心加快速度,因为它不是一个企业功能”。也许我是在玩世不恭。

        5
  •  1
  •   Desinderlase    15 年前

    你的空间索引设置正确了吗?你的边界框正确吗?所有的点都在里面吗?在您的情况下,可能HHMM for GRIDS会工作得最好(再次取决于一个花束盒)。

    你能试着用sp_help_spatial_geometry_索引,看看有什么问题吗? http://msdn.microsoft.com/en-us/library/cc627426.aspx

    你的设置有问题。空间确实是一个新功能,但也没那么糟糕。

        6
  •  1
  •   Peter Radocchia    15 年前

    你可以试着把它分成两个阶段:

    1. 在临时表w中选择候选人/ .Filter() .
    2. 查询候选者w/ .STWithin()

    如:

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

    (替换 SELECT *

    这种微优化应该是不必要的,但我以前见过相当不错的性能改进。此外,你还可以通过(1)与(2)的比率来衡量指数的选择性。

        7
  •  1
  •   Björn Harrtell    11 年前

    SQL server使用之外的实现效率问题 Quadtree index 而PostGIS使用 R-tree

    在大多数情况下,R-树是更好的算法,特别是对于几何尺寸变化的大数据集。

        8
  •  0
  •   pete    15 年前

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

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

    如果上面的方法要快得多,那么我会动态地构建sql字符串,其中嵌入参数值,这样就可以消除导致问题的参数。