Indice su una colonna calcolata persistente non ricercabile


15

Ho una tabella, chiamata Address, che ha una colonna calcolata persistente chiamata Hashkey. La colonna è deterministica ma non precisa. Ha un indice univoco su di esso che non è ricercabile. Se eseguo questa query, restituendo la chiave primaria:

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

Ricevo questo piano:

BasicPlan

Se forzo l'indice ottengo questo piano ancora peggiore:

ForceIndex

Se provo a forzare sia l'indice che una ricerca, viene visualizzato un errore:

Il processore di query non è stato in grado di produrre un piano di query a causa dei suggerimenti definiti in questa query. Reinvia la query senza specificare alcun suggerimento e senza utilizzareSET FORCEPLAN

È solo perché non è preciso? Ho pensato che non importava se fosse persistito?

C'è un modo per rendere questo indice ricercabile senza renderlo una colonna non calcolata?

Qualcuno ha collegamenti a informazioni su questo?

Non riesco a pubblicare la creazione della tabella effettiva, ma ecco una tabella di test che presenta lo stesso problema:

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 

Risposte:


12

Il problema sembra essere correlato al fatto che [TestGeocode].[ToString]()restituisce un maxtipo di dati ( nvarchar(max)).

Ho anche incontrato il problema con questa versione più semplice (cambiando la definizione di c1al varchar(8000)o utilizzando COALESCE, invece di ISNULLrisolve)

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); 

I riferimenti di colonna calcolati vengono espansi fino alla definizione sottostante, quindi abbinati successivamente alla colonna. Ciò consente di abbinare le colonne calcolate senza fare riferimento a esse per nome e consente inoltre di semplificare le operazioni sulle definizioni sottostanti.

ISNULLrestituisce il tipo di dati del primo parametro ( VARCHAR(MAX)nel mio esempio). Il tipo di ritorno COALESCEsarà anche VARCHAR(MAX)qui, ma sembra essere valutato in modo diverso in modo da evitare il problema.

Nei casi in cui la query ha esito positivo, l'output del flag di traccia include quanto segue

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))

In caso contrario, viene sostituito da

ScaOp_Identifier COL: ConstExpr1003 

Ho ipotizzato che nei casi in cui fallisce il (implicito) CAST('ABC' AS VARCHAR(MAX))viene fatto una sola volta e questo viene valutato come costante di runtime ( maggiori informazioni ). Tuttavia, il riferimento a questa etichetta della costante di runtime, anziché al valore letterale della stringa effettiva, impedisce che corrisponda alla definizione della colonna calcolata.

Questa riscrittura evita il problema nella tua query

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

Questi sintomi si manifestano a causa di un'espressione non di dimensioni considerevoli se il tipo di dati di @HashKeynon corrisponde a quello della colonna indicizzata. Potrebbe essere necessario un esplicitoCAST nell'espressione di colonna calcolata per forzare il tipo di dati desiderato.

Sulla base della tua replica, sospetto che si tratti di un bug. Ho archiviato un bug di Connect, indice della colonna calcolata non utilizzato , con una versione anche della soluzione alternativa di Martin. Sentiti libero di votare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.