我似乎无法让 SQL Server 利用对象上的基本空间索引GEOGRAPHY
来执行最简单的查询。
这里是dbfiddle.uk 复制版GEOGRAPHY
,演示了如何创建一个带有名为 的列的简单表Coordinates
,向该表添加 1 个带有多边形的行,然后在该Coordinates
列上创建空间索引。
该查询看起来应该是 SARGable,但我仍然得到聚集索引扫描,而不是在空间索引上进行非聚集索引查找:
如果我尝试强制索引提示,我会收到经典错误:
消息 8635,级别 16,状态 4,第 15 行
查询处理器无法为带有空间索引提示的查询生成查询计划。原因:空间索引不支持谓词中提供的比较器。尝试删除索引提示或删除 SET FORCEPLAN。
因此,并不是 SQL Server 认为聚集索引扫描性能更高,而是它甚至无法为空间索引提出查询计划。
根据微软关于空间索引的文档,该STDistance()
函数应该适用于空间索引可优化的谓词:
空间索引支持以下谓词形式:
- 地理1.STDistance(地理2) <= 数字
我是不是太笨了?
您链接的文档说
因此,只要您正在寻找距离函数的结果小于(或小于或等于)某个数字的情况,您就不应该看到有关“谓词中提供的比较器”无效的消息
(条件也必须如上表达 = 例如,
1 > Coordinates.STDistance(@Point)
当明确尝试强制命名空间索引时失败,原因是“原因:在条件中找不到所需的二进制空间方法”)FORCESEEK
可以使用或显式INDEX
提示(Fiddle )强制使用空间索引。显式索引提示似乎在发生故障时提供更多有用的信息。如果您确实强制使用空间索引,则执行计划将调用
[GeodeticTessellation]
表值函数传递参数@Point, 768, 9, 1, @Distance
以获取要在空间索引查找中使用的值,768
这是默认值SPATIAL_WINDOW_MAX_CELLS
,可以用相应的提示覆盖。我不确定它们9,1
对应什么。这将发出 8 行,然后用于查找空间索引,聚合将折叠此连接的结果以为每个 PK 生成一行,然后将其用于针对基表的聚集索引查找,最后有一个带有残差谓词的过滤器。负责此操作的优化器规则是
SpatialIntersectFilterOverGridIndex
。就您的示例数据而言,这比仅扫描表并针对每一行评估谓词的成本高出 45 倍(子树成本为
0.0042838
vs0.193235
)您原来的小提琴有一个表达式
WHERE Coordinates.STDistance(@Point) IS NOT NULL
。这不是可以使用空间索引的两个受支持的比较器谓词之一(除非查询还满足“最近邻居”排序STDistance
的所有条件)。STDistance()
中使用该列。WHERE
ORDER BY
PERCENT
语句。STDistance()
方法。WHERE
,则包含方法的谓词STDistance()
必须通过 AND 连接词与其他谓词连接。STDistance()
方法不能位于 WHERE 子句的可选部分。STDistance()
方法。STDistance()
子句中第一个表达式的排序顺序ORDER BY
必须是ASC
。STDistance
返回的行。NULL
这实际上最终添加了一个隐式谓词。
执行计划
工作原理与此伪代码类似
它会按顺序尝试以指数方式增加距离,并可以在迭代中停止找到至少
@N
结果并返回TOP @N
该级别的结果(如果尝试的所有距离均未找到@N
结果,则返回最终级别的结果)