Sql server 为什么';SQL Server是否在计算列上使用索引?

Sql server 为什么';SQL Server是否在计算列上使用索引?,sql-server,performance,query-optimization,sql-server-2014,database-performance,Sql Server,Performance,Query Optimization,Sql Server 2014,Database Performance,在SQL Server 2014数据库中提供以下内容: create table t ( c1 int primary key, c2 datetime2(7), c3 nvarchar(20), c4 as cast(dbo.toTimeZone(c2, c3, 'UTC') as date) persisted ); create index i on t (c4); declare @i int = 0; while @i < 10000 b

在SQL Server 2014数据库中提供以下内容:

create table t 
(
    c1 int primary key,
    c2 datetime2(7),
    c3 nvarchar(20),
    c4 as cast(dbo.toTimeZone(c2, c3, 'UTC') as date) persisted
);

create index i on t (c4);

declare @i int = 0;

while @i < 10000 
begin
    insert into t (c1, c2, c3) values
        (@i, dateadd(day, @i, '1970-01-02 03:04:05:6'), 'Asia/Manila');
    set @i = @i + 1;
end;
SQL Server后面的执行计划表明未使用
i

取而代之的是对PK上的隐式索引进行扫描,然后进行两次标量计算,最后使用查询的谓词进行筛选。我期望的执行计划是对
I
的扫描


使用中的SSDT项目尝试并复制问题。它包括CLR UDF的模拟定义。还包括我得到的执行计划。

我能够使用您所附的项目重现问题(可能与connect item的问题相同)

计算列首先展开到基础表达式,然后可能会或可能不会再与计算列匹配

您计划中的过滤器显示它已扩展到

CONVERT(date,[computed-column-index-problem].[dbo].[toTimeZone](CONVERT_IMPLICIT(datetime,[computed-column-index-problem].[dbo].[t].[c2],0),CONVERT_IMPLICIT(nvarchar(max),[computed-column-index-problem].[dbo].[t].[c3],0),CONVERT_IMPLICIT(nvarchar(max),'UTC',0)),0)>=CONVERT_IMPLICIT(date,[@1],0) 
AND 
CONVERT(date,[computed-column-index-problem].[dbo].[toTimeZone](CONVERT_IMPLICIT(datetime,[computed-column-index-problem].[dbo].[t].[c2],0),CONVERT_IMPLICIT(nvarchar(max),[computed-column-index-problem].[dbo].[t].[c3],0),CONVERT_IMPLICIT(nvarchar(max),'UTC',0)),0)<=CONVERT_IMPLICIT(date,[@2],0)
Msg 8622,16级,状态1,第27行查询处理器无法生成 由于此查询中定义的提示,查询计划无效。重新提交 查询时不指定任何提示,也不使用SET-FORCEPLAN

如果我将函数定义更改为

public static DateTime toTimeZone(DateTime dateTime,
    [SqlFacet(IsFixedLength=false, IsNullable=true, MaxSize=50)]
    string originalTimeZone,
    [SqlFacet(IsFixedLength=false, IsNullable=true, MaxSize=50)]
    string newTimeZone)
{
    return dateTime.AddHours(-8);
}
因此字符串参数变为
nvarchar(50)
。然后它能够匹配并进行搜索

具体来说,传递文本
UTC
的第二个参数需要这样做。如果注释仅应用于第一个参数,则即使有
with(forceseek)
提示,平面也不会生成搜索。如果注释仅应用于第二个参数,则它可以生成搜索-尽管平面图显示警告


以下是索引计算列的明确要求列表:检查您的情况;最可能的情况是,您需要将计算列声明为持久化的
。只需在我的实例(2014,x64 Dev Edition)上运行,我就会看到一个索引查找。所以你需要进一步完善复制这个问题的精确方法。奇怪。我再次运行了查询,这次在
I
上有一个索引搜索。但现在的问题是,我们没有
到\u时区
,所以其他任何人能够在自己的系统上复制这个的机会现在为零。@AndrewO'Brien-在提供了这个项目的情况下,至少我的2014版根本无法与之匹配,即使是提示哇。您不仅重现了问题,而且找到了问题的症结所在并找到了解决方案。@Vladimir Baranov此问题的解决方案、修复方法或解决方法是什么。我基于标识列创建了PK,计算的持久化列为('P'+右('000000000'+转换([VARCHAR](8),[ID],(0)),(7)),持久化。我以同样的方式创建了两个表,一个持久化的列。当我尝试在内部联接上联接两个持久化列时,它没有选择索引,并显示警告“类型转换表达式convert(varchar(8),id,0)可能会影响Microsoft sql server 2016-sp1cu4版本中的基数估计”
DROP TABLE IF EXISTS t 
DROP FUNCTION IF EXISTS [dbo].[toTimeZone]

GO

CREATE FUNCTION [dbo].[toTimeZone] (@newTimeZone [NVARCHAR](max))
RETURNS DATE
WITH schemabinding
AS
  BEGIN
      RETURN DATEFROMPARTS(1970, 01, 02)
  END

GO

CREATE TABLE t
  (
     c1 INT IDENTITY PRIMARY KEY,
     c4 AS dbo.toTimeZone(N'UTC') persisted
  );

CREATE INDEX i
  ON t (c4);

INSERT INTO t
DEFAULT VALUES

SELECT c1
FROM   t WITH (forceseek)
WHERE  c4 >= '1970-01-02'
       AND c4 <= '1970-03-04'; 
public static DateTime toTimeZone(DateTime dateTime,
    [SqlFacet(IsFixedLength=false, IsNullable=true, MaxSize=50)]
    string originalTimeZone,
    [SqlFacet(IsFixedLength=false, IsNullable=true, MaxSize=50)]
    string newTimeZone)
{
    return dateTime.AddHours(-8);
}