Database
 sql >> Base de Dados >  >> RDS >> Database

Se você estiver usando visualizações indexadas e MERGE, leia isto!


O colega MVP Jamie Thomson apontou recentemente que há um bug de "resultados errados" no SQL Server que pode se manifestar quando as seguintes condições forem verdadeiras:
  • Você tem uma visualização indexada que une pelo menos duas tabelas;
  • essas tabelas são restritas em qualquer direção por uma chave estrangeira de coluna única;
  • você realiza atualizações na(s) tabela(s) base usando MERGE que inclui tanto UPDATE e (EXCLUIR ou INSERIR ) ações; e,
  • você emite consultas subsequentes que fazem referência ao índice na visualização (intencionalmente ou não).

Infelizmente, o artigo da Base de Conhecimento que descreve o problema (KB # 2756471) é bastante leve em detalhes. Eles não dizem como reproduzir o problema, ou mesmo o que, especificamente, você deve procurar para ver se isso o afeta; e eles nem fazem menção a MERGE (que na verdade é o cerne do problema, não NOEXPAND , e não uma simples atualização). Existem alguns detalhes adicionais no item Connect que trouxeram a correção; esperamos que o artigo da KB seja atualizado com mais detalhes em breve.

Enquanto isso, o resultado que você pode ver são dados incorretos – ou melhor, dados obsoletos :A consulta pode mostrar a versão antiga da(s) linha(s) atualizada(s)! Passei alguns minutos tentando reproduzir esse cenário no AdventureWorks e falhei miseravelmente. Felizmente, Paul White (blog | @SQL_Kiwi) escreveu um post excelente descrevendo o cenário e mostrando uma reprodução completa do problema.

Acho que não consigo enfatizar a gravidade disso.

Certamente milhões de clientes estão usando visualizações indexadas, muitos deles migraram seu código DML para usar MERGE , e um grande número deles está na Enterprise Edition (ou não está, mas está usando o NOEXPAND dica ou estão referenciando o índice diretamente). Paul foi rápido em apontar que NOEXPAND não é necessário para reproduzir o problema no Enterprise Edition e também descobriu muitos dos outros detalhes necessários para reproduzir o bug.

Este post não tem a intenção de roubar nenhum trovão dos posts de Jamie ou Paul; apenas uma tentativa de reiterar a preocupação e aumentar a conscientização sobre esta questão. Se você tem o hábito de ignorar as atualizações cumulativas, optando por esperar pelos Service Packs, e há alguma chance de que esse problema possa estar afetando você agora, você deve a si mesmo, sem mencionar seus stakeholders e clientes, tomar esta questão a sério.

Então, o que você deve fazer?


Bem, o que você faz a seguir depende de qual versão e edição do SQL Server você está executando e se o bug realmente afeta você (ou poderia).

    SQL Server 2008 SP3
    SQL Server 2008 R2 SP1/SP2
    SQL Server 2012 RTM/SP1


    Suas opções se você estiver em uma dessas compilações:
    1. Você deve atualizar para a atualização cumulativa mais recente para seu branch:
      Branch Corrigido em CU Construir Construção mínima necessária
      para aplicar a atualização
      Artigo KB
      (Download)
      2008 Service Pack 3 CU #8 10.00.5828 10.00.5500 KB nº 2771833
      2008 R2 Service Pack 1 CU #10 10.50.2868 10.50.2500 KB nº 2783135
      2008 R2 Service Pack 2 CU #4 10.50.4270 10.00.4000 KB nº 2777358
      2012 RTM CU #5 11.00.2395 11.00.2100 KB nº 2777772
      2012 Service Pack 1 CU #2 11.00.3339 11.00.3000 KB nº 2790947

      Tabela 1:Builds que contêm a correção
    2. Se você não aplicar a correção, precisará testar todas as referências às suas visualizações para validar se elas retornam resultados corretos em todos os casos, inclusive depois de atualizar as tabelas base usando MERGE . Se isso não acontecer (ou você suspeitar que eles podem ser afetados posteriormente), você deve reconstruir o índice clusterizado em todas as exibições afetadas (ou reparar a(s) exibição(ões) indexada(s) usando DBCC CHECKTABLE , como Paul descreveu em seu post) e pare de usar MERGE nessas tabelas até aplicar a correção. Se você continuar usando MERGE contra as tabelas base, prepare-se para continuar reparando as visualizações para evitar o problema.
    3. Uma correção mais rápida seria impedir que a visualização indexada danificada fosse usada, usando qualquer um dos seguintes métodos necessários:
      • aplicar a dica de consulta OPTION (EXPAND VIEWS) a todas as consultas relevantes;
      • remova quaisquer referências explícitas ao índice na visualização;
      • no Standard ou em outras edições em que as visualizações indexadas não são correspondidas automaticamente, remova todas as instâncias de NOEXPAND .

      Mas isso, é claro, prejudicaria em grande parte o propósito da exibição indexada – pode simplesmente descartar o índice. Dito isto, geralmente é melhor obter os resultados certos lentamente do que obter os resultados errados rapidamente; então talvez esteja tudo bem.

    SQL Server 2008 RTM/SP1/SP2
    SQL Server 2008 R2 RTM


    Infelizmente, você está em uma compilação que não está mais no suporte principal e é improvável que esse problema seja corrigido para você (a menos que você esteja em suporte estendido e faça muito barulho). Portanto, suas opções são limitadas aqui – mova para uma ramificação compatível de acordo com a tabela acima e aplique a atualização cumulativa ou escolha uma das outras opções mencionadas anteriormente.

    SQL Server 2000
    SQL Server 2005


    Bem, a má notícia é que você também está em uma compilação que não é mais suportada. A boa notícia é que neste caso específico não importa – você não pode usar MERGE de qualquer forma, esse bug não pode afetá-lo.

Outros problemas de MERGE


Infelizmente, isso está longe de ser o primeiro bug que vimos com MERGE , e provavelmente não será o último. Aqui está uma seleção rápida de uma dúzia MERGE bugs que ainda estão marcados como ativos no Connect:
  • #773895:MERGE informa incorretamente violações de chave exclusivas
  • #766165:MERGE avalia o índice filtrado por linha, não pós-operação, o que causa a violação do índice filtrado
  • #723696:upsert básico de MERGE causando impasses
  • #713699:uma verificação de declaração do sistema falhou ("cxrowset.cpp":1528)
  • #699055 :planos de consulta MERGE permitem violações de restrição FK e CHECK
  • #685800:DELETE e MERGE parametrizados permitem violações de restrição de chave estrangeira
  • #654746:a mesclagem no SQL2008 SP2 ainda sofre de "Tentativa de definir o valor de uma coluna não NULL como NULL"
  • #635778 :Partes NOT MATCHED e MATCHED de uma instrução SQL MERGE não são otimizadas
  • #633132:MERGE IN WITH FILTERED SOURCE não funciona corretamente
  • #596086:bug de instrução MERGE quando INSERT/DELETE usado e índice filtrado
  • #583719:a instrução MERGE trata colunas computadas não anuláveis ​​incorretamente em alguns cenários
  • #539084 :MERGE Stmt :Condição de pesquisa em uma coluna não chave e um ORDER BY na tabela derivada de origem interrompe MERGE completamente

Agora, pode ser que alguns desses bugs tenham realmente sido corrigidos, mas seu status esteja errado porque o loop de volta ao Connect não foi fechado. Mesmo que seja esse o caso, não pode ser verdade para todos eles (e potencialmente para outros que não descobri).

Além disso, foi demonstrado por Dan Guzman que MERGE não está imune a condições de corrida e outros problemas de simultaneidade. A solução é usar HOLDLOCK (ou um nível de isolamento mais alto); no entanto, é um equívoco comum que MERGE é completamente atômico e não é propenso a esse problema. Portanto, vou me perguntar em voz alta:quantos MERGE declarações lá fora incluem HOLDLOCK (ou estão sendo executados em SERIALIZABLE )? Quantos foram exaustivamente testados para questões relacionadas à simultaneidade?

Conclusão


Pessoalmente, acho que a sintaxe é ótima (embora difícil de aprender), mas toda vez que surge um problema, corrói minha confiança na praticidade de substituir a DML existente pela nova construção.

Com isso em mente, não quero ser Chicken Little, mas não me sentiria confortável em recomendar a alguém que use MERGE a menos que implementem testes extremamente abrangentes. Alguns desses problemas também estão presentes com o padrão UPSERT metodologias, mas os problemas são mais óbvios aí. MERGE , meramente por sua natureza de declaração única, faz você querer acreditar em magia. Talvez um dia dê certo, mas agora eu sei que não vai ser capaz de serrar uma pessoa ao meio sem uma ajuda séria.