sql server - Index on a persisted computed column not seekable - Database Administrators Stack Exchange


i have table, called address, has persisted computed column called hashkey. column deterministic not precise. has unique index on not seekable. if run query, returning primary key:

select @addressid= isnull(addressid,0) dbo.[address] hashkey = @hashkey 

i plan:

basicplan

if force index worse plan:

forceindex

if try , force both index , seek, error:

query processor not produce query plan because of hints defined in query. resubmit query without specifying hints , without using set forceplan

is because it's not precise? thought didn't matter if persisted?

is there way make index seekable without making non-computed column?

does have links information on this?

i can't post actual table creation, here test table has same issue:

drop table [dbo].[test]  create table [dbo].[test]   (      [test]        [varchar](100) null,      [testgeocode] [geography] null,      [hashkey] cast(                         ( hashbytes                             ('sha',                                  ( right(replicate(' ', (100)) + isnull([test], ''), ( 100 )) )                                  + right(replicate(' ', (100)) + isnull([testgeocode].[tostring](), ''), ( 100 ))                             )                          ) binary(20)                                                                                                                               ) persisted     constraint [uk_test_hashkey] unique nonclustered([hashkey])   )     go     declare @hashkey binary(20)  select [hashkey]   [dbo].[test] (forceseek) /*query processor not produce query plan*/  [hashkey] = @hashkey  

the problem seems related fact [testgeocode].[tostring]() returns max datatype (nvarchar(max)).

i encounter issue simpler version (changing definition of c1 varchar(8000) or using coalesce instead of isnull resolves it)

drop table dbo.test  create table dbo.test   (      c1        varchar(                           max    --fails                         --  8000 --works fine                           ) null,      comp1 cast(isnull(c1, 'abc') varchar(100))     constraint uk_test_comp1 unique nonclustered(comp1)   )  go  declare @comp1 varchar(100)  select comp1   dbo.test (forceseek)  comp1 = @comp1  option (querytraceon 3604, querytraceon 8606);  

computed column references expanded out underlying definition matched column later. allows computed columns matched without referencing them name @ , allows simplification operate on underlying definitions.

isnull returns datatype of first parameter (varchar(max) in example). return type of coalesce varchar(max) here seems evaluated differently in way avoids problem.

in cases query succeeds trace flag output includes following

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

where fails replaced by

scaop_identifier col: constexpr1003  

i speculate in cases fails (implicit) cast('abc' varchar(max)) done once , evaluated runtime constant (more information). reference runtime constant label, instead of actual string literal value itself, prevents matching computed column definition.

this rewrite avoids issue in query

create table [dbo].[test]   (      [test]        [varchar](100) null,      [testgeocode] [geography] null,      [hashkey] cast(                         ( hashbytes                             ('sha',                                  ( right(space(100) + isnull([test], ''), 100) )                                  + right(space(100) + isnull(cast(right([testgeocode].[tostring](),100) varchar(100)), ''),100)                             )                          ) binary(20)                                                                                                                               ) persisted     constraint [uk_test_hashkey] unique nonclustered([hashkey])   ) 

Comments