AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 142675
Accepted
usr
usr
Asked: 2016-07-01 05:34:40 +0800 CST2016-07-01 05:34:40 +0800 CST 2016-07-01 05:34:40 +0800 CST

É legal o SQL Server preencher colunas PERSISTED com dados que não correspondem à definição?

  • 772

Estou acompanhando esta questão sobre valores estranhos em uma PERSISTEDcoluna computada. A resposta faz algumas suposições sobre como esse comportamento surgiu.

Estou perguntando o seguinte: isso não é um bug definitivo? As PERSISTEDcolunas podem se comportar dessa maneira?

DECLARE @test TABLE (
    Col1 INT,
    Contains2 AS CASE WHEN 2 IN (Col1) THEN 1 ELSE 0 END PERSISTED) --depends on Col1

INSERT INTO @test (Col1) VALUES
    (ABS(CHECKSUM(NEWID()) % 5)),
    (ABS(CHECKSUM(NEWID()) % 5)),
    (ABS(CHECKSUM(NEWID()) % 5)),
    (ABS(CHECKSUM(NEWID()) % 5)),
    (ABS(CHECKSUM(NEWID()) % 5))

SELECT * FROM @test --shows impossible data

UPDATE @test SET Col1 = Col1*1 --"fix" the data by rewriting it

SELECT * FROM @test --observe fixed data

/*
Col1    Contains2
2   0
2   0
0   1
4   0
3   0

Col1    Contains2
2   1
2   1
0   0
4   0
3   0
*/

Observe que os dados parecem "impossíveis" porque os valores da coluna calculada não correspondem à sua definição.

É bem conhecido que funções não determinísticas em consultas podem se comportar de maneira estranha, mas aqui isso parece violar o contrato de colunas computadas persistentes e, portanto, deveria ser ilegal.

Inserir números aleatórios pode ser um cenário artificial, mas e se estivéssemos inserindo NEWID()valores ou SYSUTCDATETIME()? Acho que essa é uma questão relevante que pode se manifestar de forma prática.

sql-server sql-server-2014
  • 2 2 respostas
  • 537 Views

2 respostas

  • Voted
  1. Best Answer
    Martin Smith
    2016-07-08T02:24:44+08:002016-07-08T02:24:44+08:00

    Isso é certamente um bug. O fato de os col1valores serem o resultado de uma expressão envolvendo números aleatórios claramente não altera o que o valor correto col2deveria ser. DBCC CHECKDBretorna um erro se for executado em uma tabela permanente.

    create table test (
        Col1 INT,
        Contains2 AS CASE WHEN 2 IN (Col1) THEN 1 ELSE 0 END PERSISTED);
    
    INSERT INTO test (Col1) VALUES
        (ABS(CHECKSUM(NEWID()) % 5)),
        (ABS(CHECKSUM(NEWID()) % 5)),
        (ABS(CHECKSUM(NEWID()) % 5)),
        (ABS(CHECKSUM(NEWID()) % 5)),
        (ABS(CHECKSUM(NEWID()) % 5));
    
    DBCC CHECKDB
    

    Dá (para o meu teste que tinha uma linha "impossível")

    Msg 2537, Level 16, State 106, Line 17
    Table error: object ID 437576597, index ID 0, partition ID 72057594041008128, alloc unit ID 72057594046251008 (type In-row data), page (1:121), row 0. The record check (valid computed column) failed. The values are 2 and 0.
    DBCC results for 'test'.
    There are 5 rows in 1 pages for object "test".
    CHECKDB found 0 allocation errors and 1 consistency errors in table 'test' (object ID 437576597).
    

    Também informa que

    repair_allow_data_loss é o nível mínimo de reparo para os erros encontrados pelo DBCC CHECKDB

    E, se for escolhida a opção de reparo, exclui sem cerimônia toda a linha, pois não há como saber qual coluna está corrompida.

    Anexar um depurador mostra que NEWID()está sendo avaliado duas vezes por linha inserida. Uma vez antes da CASEexpressão ser avaliada e uma vez dentro dela.

    insira a descrição da imagem aqui

    Uma possível solução alternativa pode ser usar

    INSERT INTO @test
                (Col1)
    SELECT ( ABS(CHECKSUM(NEWID()) % 5) )
    FROM   (VALUES (1),(1),(1),(1),(1)) V(X); 
    

    O que, por um motivo ou outro, evita o problema e avalia a expressão apenas uma vez por linha.

    • 9
  2. John
    2016-07-01T07:59:01+08:002016-07-01T07:59:01+08:00

    De acordo com a conversa do comentário, o consenso parece ser que a resposta à pergunta do OP é que isso constitui um bug (ou seja, deveria ser ilegal).

    O OP faz referência à análise de Vladimir Baranov no StackOverflow, onde eles afirmam:

    "Primeira vez para Col1, segunda vez para a instrução CASE da coluna persistente.

    O otimizador não sabe ou não se importa nesse caso que NEWID é uma função não determinística e a chama duas vezes."

    Dito de outra forma, deve-se esperar que [o NEWID() dentro] col1 tenha o mesmo valor que você acabou de inserir quando fez o cálculo.

    Isso seria sinônimo do que está acontecendo com o bug, onde NEWID é criado para Col1 e depois criado novamente para a coluna persistida:

    INSERT INTO @Test (Col1, Contains2) VALUES
    (NEWID(), CASE WHEN (NEWID()) LIKE '%2%' THEN 1 ELSE 0 END)
    

    Em meus testes, outras funções não determinísticas como RAND e valores de tempo não resultaram no mesmo bug.

    De acordo com Martin, isso foi enviado à Microsoft ( https://connect.microsoft.com/SQLServer/Feedback/Details/2751288 ), onde há comentários nesta página e na análise do StackOverflow (abaixo).

    • 2

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve