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

时间:2013-11-22 03:05:19

标签: sql-server

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

我的表格如下:

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

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

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

CREATE NONCLUSTERED INDEX IX_Person_PhoneNumberComparable ON Person
(
    PhoneNumberComparable ASC
)

索引都有最新的统计数据。

我的查询如下:

SELECT TOP 20 * FROM Person
WHERE PhoneNumberComparable = @PhoneNumber
ORDER BY InsertDate DESC

默认情况下,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

1 个答案:

答案 0 :(得分:5)

我相信我已经弄明白了。

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

This article(感谢评论者Kahn)说,如果“计算列中的所有函数引用与表具有相同的所有者”,则只能定义索引。

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

  • 首先,我可以创建一个索引。事实上,我甚至可以扫描索引。我只是无法让SQL对索引执行搜索。
  • 其次,据我所知,我们在这里讨论架构,而不是所有者,但两者之间的区别我仍然有些困惑。
  • 第三,我的函数与我的表在同一个模式中 - 它只是使用了与表不在同一模式中的第二个函数。