Criando índice no campo computado: string ou dados binários seriam truncados


8

Eu tenho uma tabela Foocom os seguintes campos:

ID bigint not null identity(1,1),
SerializedValue nvarchar(max),
LongValue as TRY_CAST(SerializedValue as bigint)

Agora, quero criar um índice no LongValue, para poder pesquisar facilmente valores serializados que representam números.

create nonclustered index IX_Foo on Foo(LongValue);

O que cospe o seguinte erro para mim:

Dados de seqüência ou binários seriam truncados.

Sim, existem dados no SerializedValue. Mas o que, ora, pode ser truncado criando um índice em um campo computado?

Respostas:


8

O erro não é causado pela criação do índice. O erro é causado TRY_CASTquando os valores da coluna calculada são avaliados na criação do índice.

Se eu executar isso:

SELECT TRY_CAST(REPLICATE(CONVERT(nvarchar(MAX), N'a'), 4001) AS bigint)

Eu recebo o mesmo erro.

A documentação diz (ênfase minha):

Se a conversão for bem-sucedida, TRY_CAST retornará o valor como o data_type especificado; se ocorrer um erro, nulo é retornado. No entanto, se você solicitar uma conversão explicitamente não permitida, TRY_CAST falhará com um erro.

Agora, não está exatamente claro em quais casos ele falhará com um erro (parece meio estúpido, considerando todo o ponto da função, mas de qualquer maneira ...), para que possamos corrigir o código transformando os valores de entrada (use algo razoável para os dados em sua tabela), pois não há necessidade de processar uma string enorme quando ela não couber em um bigint:

SELECT TRY_CAST(LEFT(REPLICATE(CONVERT(nvarchar(MAX), N'1'), 4001), 100) AS bigint)

Isso retorna NULLcomo o valor não é válido, mas não ocorre com erro.


-1

Se você tiver uma sequência com um valor muito longo, a criação do índice falhará. Eu tentei um pouco de código de teste usando o SQL Server 2012.

CREATE TABLE dbo.foo 
(ID bigint not null identity(1,1),
SerializedValue nvarchar(max),
LongValue as TRY_CAST(SerializedValue as bigint));

INSERT INTO dbo.foo (serializedvalue) VALUES(REPLICATE(' ', 4000)+'1');

CREATE INDEX GotToTry ON foo(LongValue);

DROP TABLE dbo.foo;
GO

Meu experimento rápido mostrou que o código funciona desde que o valor nvarchar (max) tenha 4000 caracteres ou menos. (É claro que todos os espaços em branco sem nada no final diminuem para nenhum caractere e, portanto, funcionam muito bem.) O 4001 ° caractere aciona a String or binary data would be truncatedmensagem. Portanto, você pode examinar seus dados para obter um SerializedValue com mais de 4000 caracteres.

EDIT: Sim, a conversão é para a BIGINT. O problema não é o BIGINT, mas é o NVARCHAR(MAX). Por exemplo:

  1. Se uma linha contiver '1111111111111111111', ambas serão CREATE INDEXconvertidas e o valor em BIGINT.
  2. Se uma linha é de 0 a 4000 '1s, pode CREATE INDEX, mas o valor pode ser NULLporque ele excede BIGINT.
  3. Se uma linha tiver mais de 4000 caracteres, ocorrerá uma CREATE INDEXfalha.

Portanto, parece que o conteúdo real do NVARCHAR (MAX) é o que importa para o CREATE INDEX.

EDIT: Jon Seigel identificou que o TRY_CAST dispara a falha no índice de criação quando a cadeia é maior que nvarchar (4000).


2
Isso realmente não responde à pergunta. O índice está em um bigint. Nunca vai ser outra coisa senão um bigint. A questão é por que os dados ser truncado quando um bigint é maneira dentro do subsídio tamanho de um índice
Mark Sinkinson

11
@ MarkSinkinson Editado para fornecer mais detalhes. O problema é o conteúdo do NVARCHAR (MAX).
RLF
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.