为什么SQL Server不会使用我的计算列执行索引查找

cbp*_*cbp 6 sql-server

我正在使用SQL Server 2008,它拒绝对我的索引执行搜索,该索引覆盖计算列.

我的表看起来像这样:

CREATE TABLE Person
{
    Id uniqueidentifier NOT NULL,
    InsertDate datetime NOT NULL,
    PhoneNumber NULL,
    PhoneNumberComparable AS (MakePhoneNumberComparable(PhoneNumber)) PERSISTED,
    ... etc...
}
Run Code Online (Sandbox Code Playgroud)

ID列上有一个聚簇主键索引,还有InsertDate列上的索引.

PhoneNumberComparable计算列上有一个索引,如下所示:

CREATE NONCLUSTERED INDEX IX_Person_PhoneNumberComparable ON Person
(
    PhoneNumberComparable ASC
)
Run Code Online (Sandbox Code Playgroud)

索引都具有最新的统计信息.

我的查询如下所示:

SELECT TOP 20 * FROM Person
WHERE PhoneNumberComparable = @PhoneNumber
ORDER BY InsertDate DESC
Run Code Online (Sandbox Code Playgroud)

默认情况下,SQL Server决定使用InsertDate上的索引而不是PhoneNumberComparable上的索引,从而导致性能非常差.

如果我尝试强制使用电话号码索引,通过向查询添加WITH(INDEX = IX_Person_PhoneNumberComparable),SQL将执行扫描而不是搜索.

如果我尝试使用FORCESEEK查询提示,那么SQL Server会给我以下错误:

由于此查询中定义的提示,查询处理器无法生成查询计划.重新提交查询而不指定任何提示,也不使用SET FORCEPLAN.

所以基本上,由于某种原因,SQL Server拒绝寻求我的索引!为什么?

编辑

根据评论中的建议,我简化了查询,但问题仍然存在(执行主键扫描而不是搜索电话号码索引):

SELECT TOP 20 PhoneNumberComparable  FROM Person
WHERE PhoneNumberComparable = @PhoneNumber
Run Code Online (Sandbox Code Playgroud)

cbp*_*cbp 5

我相信我已经弄明白了.

问题是由于MakePhoneNumberComparable函数使用了另一个模式下的另一个函数.要解决这个问题,我必须克隆另一个函数的第二个副本,但是在与表相同的模式下移动它.

本文(感谢评论者Kahn)说,如果"计算列中的所有函数引用与表具有相同的所有者",则只能定义索引.

好吧,这个所有权要求不仅非常令人讨厌,而且微软的文档至少可以说是非常令人困惑的:

  • 首先,我可以创建一个索引.事实上,我甚至可以扫描索引.我只是无法让SQL对索引执行搜索.
  • 其次,据我所知,我们在这里谈的是模式,而不是所有者,但两者之间的差异我仍然有点困惑.
  • 第三,我的功能在相同的模式我的表-它只是利用了第二个功能是不是在同一个模式的表.