我正在努力将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
处无用),它是没有那么糟糕,但仍然不擅长)。
我能够获得使用的索引,它只是没有帮助。每个测试都在启用“显示实际执行计划”的情况下运行,并且始终显示索引。
答案 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)
我刚刚度过了类似的问题。特别是,我们正在进行多边形点类型的查询,其中有一组相对较小的多边形,但每个多边形都很大且复杂。
对于多边形表上的空间索引,解决方案如下:
这产生了巨大的变化。它比默认配置中的空间索引快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)
您可以尝试将其分为两遍:
.Filter()
。.STWithin()
。例如:
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字符串,这样你就可以删除引起问题的参数。