Casos do Dia a Dia – Could not complete cursor operation because the table schema changed after the cursor was declared

Fala pessoal,

Nesse post vou compartilhar mais um Caso do Dia a Dia, dessa vez explicando a mensagem de erro abaixo ao utilizar um CURSOR.

“Could not complete cursor operation because the table schema changed after the cursor was declared”


Caso do Dia a Dia – Erro ao utilizar um Cursor:

De forma bem resumida, o CURSOR pode ser utilizado em LOOPs no SQL Server. Existem quatro tipos de cursores:

  • forward-only
  • static
  • keyset
  • dynamic

Mais detalhes no link abaixo da documentação oficial da Microsoft:

https://learn.microsoft.com/en-us/sql/relational-databases/cursors?view=sql-server-ver16

Vamos iniciar o nosso cenário de testes criando e populando uma tabela com quatro registros. Também criei uma Primary Key na coluna ID.

No teste 1, mostro a sintaxe básica para percorrer cada registro do CURSOR e exibir o resultado.

Até aqui tudo bem! Agora propositalmente vou incluir um WAITFOR DELAY dentro do cursor para fazer a execução demorar alguns segundos e em paralelo (em uma outra sessão) vou executar um REBUILD nessa mesma tabela “tb_test”. Ao fazer isso, vamos ter o erro abaixo:

“Could not complete cursor operation because the table schema changed after the cursor was declared”

O erro acontece porque o CURSOR utiliza a tabela “tb_test” e durante a sua execução ela teve uma alteração (nesse caso, foi o REBUILD). Com isso, quando o SQL Server vai executar a próxima iteração do CURSOR ele falha!

No link abaixo, temos uma ótima resposta do Aaron Bertrand, onde ele sugere alterar o tipo do CURSOR para STATIC, pois dessa forma será feita uma cópia temporária dos dados para que o cursor não seja impactado por outras alterações.

“but static makes a copy of the data so that the cursor isn’t impacted (well, doesn’t care about) any of those changes.”

https://dba.stackexchange.com/questions/218760/could-not-complete-cursor-operation-because-the-table-schema-changed-after-the-c

Portanto, ao alterar o tipo para CURSOR STATIC, não vamos ter mais o erro, pois como foi explicado, ele faz uma cópia temporária dos dados e as alterações na tabela não irão afetá-lo. Lembrando que ao fazer isso estaremos consumindo mais recursos OK.

Por fim, o próprio link da documentação oficial da Microsft recomenda utilizar um WHILE ao invés do CURSOR nesses casos em que a tabela possui uma Primary Key, para evitar uma sobrecarga no CURSOR com a cópia temporária dos dados.

“In some scenarios, if there’s a primary key on a table, a WHILE loop can be used instead of a cursor, without incurring in the overhead of a cursor.”

https://learn.microsoft.com/en-us/sql/relational-databases/cursors?view=sql-server-ver16

“Ah Luiz, então o CURSOR é SEMPRE PIOR do que um WHILE?”

Não estou dizendo isso, mas mostrei um caso em que o WHILE poderia ser melhor. Para outras situações pode ser que o mais recomendado seja um CURSOR. Você precisa entender bem cada cenário e as limitações de cada um deles para fazer a melhor escolha. Eu particularmente prefiro o WHILE. =)


Espero que tenha gostado e que isso também possa ser útil no seu dia a dia. Até o próximo post!

Me siga no LinkedIn e YouTube para ficar por dentro das novidades.

Abraço,

Luiz Vitor França Lima

Consultor SQL Server

2 comentários em “Casos do Dia a Dia – Could not complete cursor operation because the table schema changed after the cursor was declared

  1. José Dız (Porto SQL) Responder

    Que erro curioso… Quem trabalha com diversos cenários no dia a dia, como o pessoal da Power Tuning, depara com situações bizarras… É um aprendizado contínuo!

    Em casos de somente leitura dos dados do cursor, geralmente a opção FAST_FORWARD é o suficiente para evitar a situação citada e melhorar o desempenho, conforme você mesmo cita em seu artigo.

    Mas melhor ainda se substituir o cursor por tratamento de conjunto de linhas (“dataset”), né?

    • Luiz Lima Autor do postResponder

      Exatamente José, cada dia uma surpresa diferente kkk. Sempre que for possível evitar utilizar CURSOR / WHILE e não precisar fazer algo linha a linha seria o melhor cenário mesmo.

      Mas quando não tiver jeito, tem que entender se tem uma Primary Key envolvida e talvez seja melhor utilizar um WHILE, igual comentei no post.

      Obrigado pelo comentário!

      Abraço,
      Luiz Lima

Deixe uma resposta