Індекс на збереженому обчисленому стовпчику не можна знайти


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, індекс обчислених стовпців не використовується , і версія способу вирішення справи Мартіна. Не соромтеся голосувати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.