Ответ 1
Я смог воспроизвести проблему, используя ваш подключенный проект (это, вероятно, та же проблема, что и здесь, со ссылкой на элемент здесь)
вычисляемые столбцы сначала раскрываются в основное выражение, а затем могут или не могут быть возвращены обратно в вычисленный столбец позже.
Фильтр в вашем плане показывает, что он расширяется до
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)
Эти неявные отбрасывания на nvarchar(max)
оказываются наносящими урон. Простым воспроизведением, не требующим CLR, является
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';
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)
. Если аннотация применяется только к второму параметру, тогда она может вызвать поиск, хотя в плане отображается предупреждение.