11

我正在努力将一些空间搜索功能从带有 PostGIS 的 Postgres 转移到 SQL Server,我看到一些非常糟糕的性能,即使使用索引也是如此。

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

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

如果我选择一个相当小的形状,有时我可以得到亚秒级的时间,但如果我的形状相当大(有时是这样),我可以得到超过 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
  )

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

对于这些测试,我使用 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,它还不错,但仍然不擅长)。

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

4

8 回答 8

5

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

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

  1. 使用“几何自动网格”而不是旧的 MMLL 等。这提供了 8 级索引而不是旧的 4 级,并且设置是自动的。和...
  2. 将“每个对象的单元格”设置为 2000 或 4000。(这不是一件容易猜测的事情,因为默认值为 16!)

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

于 2013-05-17T04:23:04.777 回答
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

和:

-- 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
于 2010-08-12T17:15:42.370 回答
2

除了 SQL server 使用Quadtree 索引,而 PostGIS 使用R-tree索引之外的实施效率问题。

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

于 2014-06-23T08:44:22.377 回答
2

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

我也不确定您为什么要从 Postgres 迁移。

于 2010-08-12T17:20:56.587 回答
2

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

于 2010-08-26T17:31:48.847 回答
1

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

  1. 将候选人选择到带有.Filter().
  2. 查询候选人 w/ .STWithin()

例如:

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

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

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

于 2010-08-28T04:11:56.490 回答
1

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

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

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

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

于 2010-08-26T16:58:01.227 回答
0

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

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

如果上面要快得多,那么我将使用嵌入在字符串中的参数值动态构建您的 sql 字符串,这样您就可以删除导致问题的参数。

于 2010-08-23T06:58:10.023 回答