Индекс для сохраняемого вычисляемого столбца недоступен для поиска

15

У меня есть таблица с именем Address, которая имеет сохраненный вычисляемый столбец с именем Hashkey. Столбец является детерминированным, но не точным. У него есть уникальный индекс, который нельзя найти. Если я запускаю этот запрос, возвращая первичный ключ:

SELECT @ADDRESSID= ISNULL(AddressId,0)
FROM dbo.[Address]
WHERE HashKey = @HashKey

Я получаю этот план:

BasicPlan

Если я форсирую индекс, я получаю еще худший план:

ForceIndex

Если я пытаюсь форсировать индекс и поиск, я получаю сообщение об ошибке:

Обработчику запросов не удалось создать план запроса из-за подсказок, определенных в этом запросе. Повторите запрос без указания каких-либо подсказок и без использованияSET FORCEPLAN

Это только потому, что это не точно? Я думал, что это не имеет значения, если это было продолжено?

Есть ли способ сделать этот индекс доступным для поиска, не делая этот столбец не вычисляемым?

У кого-нибудь есть ссылки на информацию по этому поводу?

Я не могу опубликовать фактическое создание таблицы, но вот тестовая таблица с той же проблемой:

drop TABLE [dbo].[Test]

CREATE TABLE [dbo].[Test]
  (
     [test]        [VARCHAR](100) NULL,
     [TestGeocode] [geography] NULL,
     [Hashkey] AS CAST(
                        ( hashbytes
                            ('SHA', 
                                ( RIGHT(REPLICATE(' ', (100)) + isnull([test], ''), ( 100 )) ) 
                                + RIGHT(REPLICATE(' ', (100)) + isnull([TestGeocode].[ToString](), ''), ( 100 ))
                            ) 
                        ) AS BINARY(20)                                                                                                        
                      ) PERSISTED
    CONSTRAINT [UK_Test_HashKey] UNIQUE NONCLUSTERED([Hashkey])
  )    
GO    
DECLARE @Hashkey BINARY(20)

SELECT [Hashkey]
FROM   [dbo].[Test] WITH (FORCESEEK) /*Query processor could not produce a query plan*/
WHERE  [Hashkey] = @Hashkey 
Пол Уайт восстановил Монику
источник

Ответы:

12

Кажется, проблема связана с тем, что [TestGeocode].[ToString]()возвращает maxтип данных ( nvarchar(max)).

Я также сталкиваюсь вопрос с этой простой версией (изменение определения c1к varchar(8000)или используя COALESCEвместо ISNULLрешает это)

DROP TABLE dbo.Test

CREATE TABLE dbo.Test
  (
     c1        VARCHAR(
                          MAX    --Fails
                        --  8000 --Works fine
                          ) NULL,
     comp1 AS CAST(ISNULL(c1, 'ABC') AS VARCHAR(100))
    CONSTRAINT UK_Test_comp1 UNIQUE NONCLUSTERED(comp1)
  )

GO

DECLARE @comp1 VARCHAR(100)

SELECT comp1
FROM   dbo.Test WITH (FORCESEEK)
WHERE  comp1 = @comp1 
OPTION (QUERYTRACEON 3604, QUERYTRACEON 8606); 

Вычисленные ссылки на столбцы расширяются до базового определения, а затем сопоставляются со столбцом позже. Это позволяет сопоставлять вычисляемые столбцы, не ссылаясь на них по имени, а также позволяет упрощению работать с базовыми определениями.

ISNULLвозвращает тип данных первого параметра ( VARCHAR(MAX)в моем примере). Тип возврата COALESCEтакже будет VARCHAR(MAX)здесь, но, похоже, он оценивается по-разному, чтобы избежать проблемы.

В случаях, когда запрос завершается успешно, вывод флага трассировки включает в себя следующее

ScaOp_Convert varchar(max) collate 49160,Null,Var,Trim,ML=65535

    ScaOp_Const TI(varchar collate 49160,Var,Trim,ML=3) 
                      XVAR(varchar,Owned,Value=Len,Data = (3,ABC))

Где это терпит неудачу, это заменяется

ScaOp_Identifier COL: ConstExpr1003 

Я предполагаю, что в тех случаях, когда он терпит неудачу (неявное) CAST('ABC' AS VARCHAR(MAX))выполняется только один раз, и это оценивается как постоянная времени выполнения ( дополнительная информация ). Однако ссылка на эту метку константы времени выполнения вместо самого фактического строкового литерала не позволяет ему соответствовать определению вычисляемого столбца.

Эта перезапись позволяет избежать проблемы в вашем запросе

CREATE TABLE [dbo].[Test]
  (
     [test]        [VARCHAR](100) NULL,
     [TestGeocode] [geography] NULL,
     [Hashkey] AS CAST(
                        ( hashbytes
                            ('SHA', 
                                ( RIGHT(SPACE(100) + isnull([test], ''), 100) ) 
                                + RIGHT(SPACE(100) + isnull(CAST(RIGHT([TestGeocode].[ToString](),100) AS VARCHAR(100)), ''),100)
                            ) 
                        ) AS BINARY(20)                                                                                                        
                      ) PERSISTED
    CONSTRAINT [UK_Test_HashKey] UNIQUE NONCLUSTERED([Hashkey])
  )
Мартин Смит
источник
0

Вы получите эти симптомы из-за невыраженного выражения, если тип данных @HashKeyне соответствует индексируемому столбцу. Вам может понадобиться явное CASTвыражение в вычисляемом выражении столбца, чтобы привести к желаемому типу данных.

Основываясь на вашем репро, я подозреваю, что это ошибка. Я отправил сообщение об ошибке Connect, индекс вычисляемого столбца не используется , а также версию обходного пути Мартина. Не стесняйтесь голосовать.

Дэн Гусман
источник