quarta-feira, 23 de setembro de 2009

Rowlock no SQL Server não funciona

Me deparei esses dias com esse problema. Até ontem achei que o with (rowlock) do SQL Server funcionava. Resolvi escrever aqui um passo-a-passo para comprovar que não funciona.

Nesse exemplo, o SQL Server precisa fazer um lock exclusivo na tabela referenciada por uma FK. Nesse exemplo, é a Tabela1. Quando o SQL Server faz um insert na Tabela2, e um delete na Tabela1, ele precisa locar toda a Tabela2, pois ela tem uma FK para a Tabela1. Como a Tabela2 está locada para inclusão, o delete fica aguardando a liberação.

Esse problema só é resolvido com a criação de índices. O rowlock parece não fazer efeito, mesmo com o índice.

Vamos entender melhor no passo-a-passo abaixo. Começamos com a criação do modelo de dados.

Tabela1

Chave1 (int) not null IDENTITY

Valor1 (varchar(10)) not null

Tabela2

Chave2 (int) IDENTITY

Valor2 (varchar(10)) not null

Chave1 (int) null, FK para Tabela1

Feito isso, vamos incluir 10 registros em cada tabela, mantendo a Chave1 em Tabela2 sempre nulo.

Exemplo de dados das tabelas:

Chave1

Valor1

1

VT1 - 1

2

VT1 - 2

3

VT1 - 3

4

VT1 - 4

5

VT1 - 5

6

VT1 - 6

7

VT1 - 7

8

VT1 - 8

9

VT1 - 9

10

VT1 - 10

Tabela 1: Exemplo da tabela 1

Chave2

Valor2

Chave1

1

VT2 - 1

NULL

2

VT2 - 2

NULL

3

VT2 - 3

NULL

4

VT2 - 4

NULL

5

VT2 - 5

NULL

6

VT2 - 6

NULL

7

VT2 - 7

NULL

8

VT2 - 8

NULL

9

VT2 - 9

NULL

10

VT2 - 10

NULL

Tabela 2: Exemplo da tabela 2

Executar os comandos em janelas distintas:

1. Janela 1

begin tran;

insert into Tabela2 with (rowlock) (valor2) values ('NT2 - 1')

2. Janela 2

begin tran;

delete from Tabela1 with (rowlock) where chave1 = 5

3. Aqui o problema já ocorre! A Janela 2 fica aguardando a execução da Janela 1.

4. Libere a Janela 1 com o comando: rollback tran;

5. Faça o mesmo na Janela 2.

O esperado seria locar apenas um registro no insert. Esse problema só pode ser resolvido se for colocado um índice na Tabela2 para a coluna Chave1.