Preparação para o Exame de Certificação DB2 10.1 Fundamentals (Exame 610), Parte 6: Simultaneidade de Dados

Este artigo se destina a apresentar o conceito de consistência de dados e os mecanismos que o DB2® usa para mantâ-la em ambientes de banco de dados de usuário único e multiusuário. Também ajudará você a se preparar para a Seção 6 do exame de certificação DB2 10.1 Fundamentals (Exame 610).

Roger E. Sanders, Senior Consultant Corporate Systems Engineer, EMC Corporation

Roger SandersRoger E. Sanders é diretor-presidente da Roger Sanders Enterprises Inc. e Senior Consultant Corporate Systems Engineer na EMC Corp. Ele trabalha com DB2 para Linux, UNIX e Windows desde que o DB2 foi introduzido no computador pessoal IBM (como parte do OS/2 1.3 Extended Edition) e trabalha no segmento de mercado de armazenamento há mais de uma década. Ele escreveu artigos para o IDUG Solutions Journal e Certification Magazine, escreveu tutoriais e artigos sobre o DB2 para o IBM developerWorks, apresentou-se em diversas conferências/reuniões do International DB2 Users Group (IDUG) e Regional DB2 Users Group (RUG), lecionou diversas aulas sobre os Fundamentos do DB2 e a administração do banco de dados do DB2 para LUW e é autor de 21 livros sobre o DB2 e um livro sobre o ODBC. Durante os últimos nove anos, ele escreve a coluna Distributed DBA na IBM Data Management Magazine (antiga DB2 Magazine) e ajuda a IBM a desenvolver 18 exames de certificação do DB2 para LUW. De 2008 a 2012, foi reconhecido como IBM Champion (pelo gerenciamento de dados); em 2010, foi reconhecido como IBM developerWorks Contributing Author, e, em 2011, como IBM developerWorks Professional Author.



25/Set/2012

Antes de Iniciar

Sobre esta série

Você está pensando em obter a — certificação Fundamentos do DB2 10.1 do IBM Certified Database Associate? Nesse caso, veio ao local certo. Esta série de preparação para a certificação do DB2 10.1 se destina a abordar todos os tópicos que é necessário conhecer antes de fazer o exame de certificação DB2 10.1 Fundamentals (Exame 610). Mesmo se você não está pensando em obter a certificação agora, as informações apresentadas nesta série podem ajudar você a aprender muitos dos recursos e das funcionalidades disponíveis no DB2 10 para z/OS® e DB2 10.1 para Linux®, UNIX® e Windows®.

Sobre este tutorial

Treze por cento do exame de certificação DB2 10.1 Fundamentals (Exame 610) se destina a testar o seu conhecimento dos mecanismos que o DB2 usa para permitir que vários usuários e aplicativos interajam com um banco de dados sem prejudicar a consistência de dados. As perguntas que constituem esta parte do exame se destinam a avaliar:

  • A sua capacidade de identificar o nível de isolamento apropriado para ser usado em uma determinada situação.
  • A sua capacidade de identificar as características dos bloqueios do DB2.
  • A sua capacidade de listar objetos para os quais é possível adquirir bloqueios.
  • A sua capacidade de identificar fatores que podem influenciar os bloqueios.

Este tutorial se destina a apresentar o conceito de consistência de dados e os dois mecanismos que o DB2 usa para manter a consistência de dados em ambientes de banco de dados de usuário único e multiusuário: níveis de isolamento e bloqueios. Este é o sexto e último tutorial de uma série que pode ser usada para ajudá-lo a se preparar para o exame de certificação DB2 10.1 Fundamentals (Exame 610).

Objetivos

O material deste tutorial aborda os objetivos na Seção 6 do exame de certificação DB2 10.1 Fundamentals (Exame 610). (É possível visualizar esses objetivos em http://www-03.ibm.com/certify/tests/obj610.shtml.)

Após concluir este tutorial, você deve poder:

  • Identificar os fatores que influenciam os bloqueios.
  • Listar objetos nos quais é possível obter bloqueios.
  • Utilizar a instrução LOCK TABLE adequadamente.
  • Identifique as características dos bloqueios do DB2 (bloqueios comuns compartilhados em toda a plataforma).
  • Identificar níveis de isolamento que devem ser usados em uma determinada situação.
  • Saber como e quando usar a semântica atualmente confirmado (CC).

Pré-requisitos

Para entender parte do material apresentado aqui, é necessário estar familiarizado com os termos a seguir:

  • Linguagem de Consulta Estruturada (SQL)— Uma linguagem padronizada usada para definir objetos e manipular dados em um banco de dados relacional.
  • Objeto— Qualquer coisa em um banco de dados que pode ser criada ou manipulada com SQL (por exemplo, tabelas, visualizações, índices, pacotes, etc.).
  • Tabela— Uma estrutura lógica usada para apresentar dados como uma coleção de linhas não ordenadas com um número fixo de colunas. Cada coluna contém um conjunto de valores, cada valor com o mesmo tipo de dado. As definições das colunas constituem a estrutura da tabela, e as linhas contêm os dados reais.
  • Registro— A representação de armazenamento de uma linha em uma tabela.
  • Campo— A representação de armazenamento de uma coluna em uma tabela.
  • Valor— Um item de dados específico que pode ser localizado em cada intersecção de linha e coluna de uma tabela.
  • Otimizador do DB2— Um componente do pré-compilador de SQL que escolhe um plano de acesso para uma instrução SQL de Linguagem de Manipulação de Dados (DML) modelando o custo de execução de diversos planos de acesso alternativos e escolhendo aquele com o custo mínimo estimado.

Requisitos do Sistema

Não é necessário ter uma cópia do DB2 para realizar esse tutorial — no entanto, se você tiver acesso a um servidor de banco de dados do DB2, poderá testar alguns comandos e conceitos apresentados.

É possível fazer o download de uma cópia gratuita do DB2 Express-C da IBM.


Consistência de dados

Entendendo consistência de dados

Para entender como o DB2 tenta manter a consistência de dados em ambientes de usuário único e multiusuário, primeiro é preciso entender o que é a consistência de dados. Além disso, você deve ser capaz de identificar os tipos de eventos que podem deixar um banco de dados em um estado inconsistente. Então, o que é a consistência de dados? A melhor forma de responder essa pergunta é examinar um exemplo.

Suponha uma empresa proprietária de uma cadeia de restaurantes use o banco de dados para controlar, entre outras coisas, o inventário de cada restaurante. O banco de dados contém tabelas de inventário para todos os restaurantes da cadeia e, conforme o restaurante recebe e usa os seus suprimentos, a tabela de inventário correspondente é atualizada. Suponha agora que uma caixa de café seja movida fisicamente de um restaurante (que tem bastante café no estoque) para outro (que acabou de ficar sem café). Para refletir esse movimento de inventário, o valor das latas de café armazenadas na tabela de inventário do restaurante receptor tem que ser elevado, e o valor das latas de café armazenadas na tabela de inventário do restaurante doador têm que ser reduzido. Se o usuário aumenta o valor das latas de café na tabela do restaurante receptor, mas não baixa o valor na tabela do restaurante doador, os dados do banco de dados não terão consistência. O valor total de latas de café referente a toda a cadeia e o referente ao restaurante doador não são mais precisos.

Em ambientes de usuário único, o banco de dados pode ficar inconsistente se o usuário não faz as mudanças necessárias (como no exemplo anterior), se o sistema de banco de dados trava enquanto um usuário ou aplicativo está fazendo mudanças ou se um aplicativo é finalizado prematuramente. Em ambientes de multiusuário, também pode haver inconsistência quando vários usuários ou aplicativos tentam acessar os mesmos dados ao mesmo tempo. Por exemplo, dado o cenário que acabamos de apresentar, se um usuário consulta o banco de dados para obter a contagem de latas de café do restaurante receptor ao passo que outro usuário está atualizando as tabelas de inventário dos dois restaurantes para mostrar que uma lata de café foi movida de um restaurante para outro antes da confirmação das atualizações, a consulta indicará erroneamente que não há mais latas de café disponíveis.


Transações, níveis de isolamento e bloqueios

Transações

O principal mecanismo que o DB2 usa para manter a consistência de dados é a transação. A transação (também conhecida como unidade de trabalho) é uma sequência recuperável de uma ou mais operações SQL agrupadas como uma unidade, geralmente dentro de um aplicativo. O início e o término de uma transação definem pontos de consistência dentro de um banco de dados. Os efeitos de todas as operações realizadas dentro de uma transação são aplicados ao banco de dados e se tornam permanentes (são confirmados) ou são retrocedidos (sofrem retrocesso), e o banco de dados volta ao estado em que se encontrava antes do início da transação. Em ambientes de usuário único, as transações são executadas serialmente e não têm que concorrer com transações simultâneas. No entanto, em ambientes de multiusuário, as transações frequentemente são executadas de forma simultânea. Consequentemente, cada transação tem o potencial de interferir em qualquer outra transação em execução; o nível real permitido de interferência é controlado por outro mecanismo: o nível de isolamento.

As transações que têm o potencial de interferir umas nas outras são denominadas intercaladas ou paralelas), ao passo que as transações completamente isoladas umas das outras são consideradas serializáveis, ou seja, os resultados de sua execução simultânea não serão diferentes dos resultados da execução serial (uma depois da outra). Idealmente, todas as transações deveriam ser serializáveis. Por quê? Suponha que um vendedor e um contabilista estão trabalhando no mesmo banco de dados ao mesmo tempo. Agora, suponha que o vendedor faz um pedido na Empresa X (para gerar uma cotação), mas não confirma a entrada. Ao mesmo tempo, o contabilista consulta o banco de dados para obter uma lista de todos os pedidos não pagos, recupera o novo pedido para a Empresa X e gera uma nota. Suponha agora que a pessoa com quem o vendedor está trabalhando na Empresa X decide não fazer o pedido. O vendedor retrocede a transação porque o pedido não foi realizado, e as informações do pedido são removidas do banco de dados. Entretanto, uma semana depois, a Empresa X recebe a nota referente ao pedido — que nunca foi realizado. Se a transação do vendedor e a do contabilista tivessem sido totalmente isoladas uma da outra (ou seja, serializadas), essa situação não teria acontecido. A transação do vendedor teria sido finalizada antes do início da transação do contabilista ou a transação do contabilista teria terminado antes do início da transação do vendedor. Em qualquer caso, a Empresa X não teria recebido uma nota.

Quando as transações não são serializáveis, podem ocorrer quatro tipos de fenômenos:

  • Atualizações perdidas— Isso ocorre quando duas transações leem os mesmos dados e tentam atualizá-los ao mesmo tempo, provocando a perda de uma das atualizações. Por exemplo, a Transação 1 e a Transação 2 leem a mesma linha de dados e calcula novos valores para ela com base nos valores originais lidos. Se a Transação 1 atualiza a linha com o novo valor e a Transação 2 atualiza, em seguida, a mesma linha, a operação de atualização realizada pela Transação 1 é perdida.
  • Leituras Sujas— Isso ocorre quando uma transação lê dados que ainda não foram confirmados. Por exemplo, a Transação 1 altera uma linha de dados, e a Transação 2 lê a linha alterada antes da confirmação da mudança. Se a Transação 1 retrocede a mudança, a Transação 2 lê dados que nunca existiram realmente.
  • Leituras não Repetidas— Isso ocorre quando uma transação lê a mesma linha de dados duas vezes e obtêm resultados diferentes em cada ocasião. Por exemplo, a Transação 1 lê uma linha de dados e, em seguida, a Transação 2 modifica ou exclui essa linha e confirma a mudança. Quando a Transação 1 tentar ler novamente a linha, ela recuperará diferentes valores de dados (se a linha tiver sido atualizada) ou descobrirá que a linha não existe mais (se a linha tiver sido excluída).
  • Fantasmas— Isso ocorre quando uma linha de dados corresponde a alguns critérios de procura, mas não é vista inicialmente. Por exemplo, a Transação 1 recupera um conjunto de linhas que preenchem alguns critérios de procura e, e, em seguida, a Transação 2 insere uma nova linha que corresponde aos critérios de procura da consulta da Transação 1. Se a Transação 1 executa novamente a consulta que produziu o conjunto de linhas original, será retornado um conjunto de linhas diferente. (Agora a nova linha adicionada pela Transação 2 será incluída no conjunto de linhas que é produzido).

Níveis de isolamento

É possível que diversos usuários e aplicativos precisem acessar ou modificar dados armazenados em um banco de dados do DB2 ao mesmo tempo; portanto, o DB2 deve ser capaz de permitir que as transações executem simultaneamente e, ao mesmo tempo, garantir que a integridade de dados nunca seja comprometida. O compartilhamento simultâneo de recursos de bancos de dados por vários usuários ou aplicativos é conhecido como simultaneidade. Uma das formas pelas quais o DB2 faz cumprir a simultaneidade é o uso de níveis de isolamento. Como o próprio nome indica, os níveis de isolamento determinam como os dados acessados ou modificados por uma transação são "isolados" de outras transações que estão ocorrendo ao mesmo tempo. O DB2 10.1 reconhece e suporta os seguintes níveis de isolamento:

  • Leitura Repetida
  • Estabilidade de Leitura
  • Estabilidade do Cursor
  • Leitura Não Confirmada

Tablela 1 mostra os vários fenômenos que podem ocorrer quando cada um desses níveis de isolamento é usado.

Tablela 1. Fenômenos que podem ocorrer quando cada nível de isolamento é usado
Nível de isolamentoFenômenos
Atualizações perdidasLeituras SujasLeituras não RepetidasFantasmas
Leitura RepetidaNãoNãoNãoNão
Estabilidade de LeituraNãoNãoNãoSim
Estabilidade do CursorNãoNãoSimSim
Leitura Não ConfirmadaNãoSimSimSim

O nível de isolamento de Leitura Repetida

O nível de isolamento de leitura repetida é o mais restritivo. Nesse nível, os efeitos de uma transação são isolados completamente dos efeitos de outras transações que estão executando simultaneamente. Sendo assim, não existe a possibilidade de ocorrência de atualizações perdidas, leituras sujas ou não repetidas e fantasmas.

Quando se usa o nível de isolamento de leitura repetida, todas as linhas mencionadas de alguma forma pela transação proprietária são bloqueada durante a transação. Consequentemente, se a mesma consulta (instrução SELECT ) é emitida várias vezes dentro da mesma transação, existe a garantia de que os conjuntos de dados dos resultados produzidos sejam idênticos. Na verdade, as transações que executam sob o nível de isolamento de leitura repetida podem recuperar o mesmo conjunto de linhas várias vezes e realizar várias operações nelas, até serem finalizadas (por uma operação de confirmação ou retrocesso). Outras transações ficam proibidas de realizar operações de inserção, atualização ou exclusão que alterariam uma linha (ou mais) acessada pela transação proprietária, desde que a transação esteja ativa.

Para assegurar que os dados que estão sendo acessados por uma transação executando sob o nível de isolamento de leitura repetida não sejam prejudicados por outras transações, todas as linhas referenciadas pela transação de isolamento são bloqueadas — não só as linhas efetivamente recuperadas ou modificadas. Sendo assim, se uma transação varre 1.000 linhas para recuperar 10, bloqueios são adquiridos e mantidos em todas as 1.000 linhas varridas — não só nas 10 linhas recuperadas.

OBSERVAÇÃO: quando se usa o nível de isolamento de leitura repetida, se uma tabela ou visualização inteira é varrida em resposta a uma consulta, ou a tabela inteira ou somente as linhas referenciadas pela visualização são bloqueadas. Isso reduz muito a simultaneidade, principalmente quando tabelas e visualizações grandes são usadas.

Portanto, como esse nível de isolamento funciona em uma situação concreta? Suponha que você seja o proprietário de um pequeno motel e use um banco de dados DB2 para controlar as informações de reservas e taxas dos quartos. Você também tem um aplicativo baseado na web que permite reservar quartos adotando o esquema de atender por ordem de chegada. Se o seu aplicativo de reserva executa sob o nível de isolamento de leitura repetida, um cliente que varre o banco de dados procurando uma lista de quartos disponíveis em um determinado intervalo de datas impede que outros clientes façam ou cancelem reservas que fariam com que a lista mudasse caso ela tivesse que ser gerada outra vez (executando a mesma consulta — supondo, obviamente, que a consulta seja executada a partir da mesma transação). Da mesma forma, o gerente do seu motel não poderá alterar a taxa do quarto de nenhum dos registros de quarto varridos em resposta à consulta do primeiro cliente. Outros clientes seriam capazes de fazer ou cancelar reservas de quartos cujos registros não foram varridos quando a consulta do primeiro cliente foi executada. Analogamente, o seu gerente poderia alterar as taxas de quarto de qualquer registro de quarto que não foi lido quando a lista de quartos disponíveis foi produzida. (Qualquer pessoa que tente fazer ou cancelar reservas de quartos ou alterar as taxas dos quartos cujos registros foram varridos em resposta à consulta do primeiro cliente terá que esperar até que a transação do primeiro cliente seja finalizada). Figura 1 mostra isso.

Figura 1. Exemplo de como o nível de isolamento de leitura repetida pode afetar o comportamento do aplicativo
Exemplo de como o nível de isolamento de leitura repetida pode afetar o comportamento do aplicativo

O nível de isolamento de Estabilidade de Leitura

O nível de isolamento estabilidade de leitura não é tão restritivo quanto o nível de isolamento de leitura repetida. Portanto, ele não isola totalmente uma transação do efeito de outras transações que executam simultaneamente. Quando se usa esse nível de isolamento, não é possível a ocorrência de atualizações perdidas, leituras sujas e não repetidas, mas fantasmas podem ser observados. Isso acontece porque, quando se usa o nível de isolamento estabilidade de leitura, somente as linhas efetivamente recuperadas ou modificadas pela transação em isolamento são bloqueadas. Sendo assim, se uma transação varre 1.000 linhas para recuperar 10, os bloqueios só são adquiridos e mantidos nas 10 linhas recuperadas, não nas 1.000 linhas varridas. Como são adquiridos menos bloqueios, mais transações podem executar simultaneamente. Se a mesma consulta é executada várias vezes pela transação em isolamento, o conjunto de dados de resultados que é produzido pode ser diferente em cada ocasião.

Assim como acontece no nível de isolamento de leitura repetida, as transações que executam sob o nível de isolamento estabilidade de leitura podem recuperar um conjunto de linhas e realizar várias operações nelas. Outras transações são proibidas de realizar operações de atualização e exclusão que afetem o conjunto de linhas que a transação em isolamento recuperou (enquanto a transação permanecer ativa). Por outro lado, outras transações podem realizar operações de inserção em qualquer tabela ou visualização passível de atualização no banco de dados; as linhas inseridas que corresponderem aos critérios de seleção de uma consulta emitida pela transação em isolamento aparecerão como fantasmas em quaisquer conjuntos de dados de resultados subsequentes que forem produzidos.

Então, como esse nível de isolamento muda o funcionamento do aplicativo de reservas do seu motel? Agora, quando um cliente varre o banco de dados para obter uma lista de quartos disponíveis em um determinado intervalo de datas, outros clientes poderão fazer ou cancelar reservas que podem alterar a lista do primeiro cliente caso ela seja gerada outra vez (executando a mesma consulta — supondo que a consulta seja executada a partir da mesma transação). Da mesma forma, o seu gerente poderá alterar a taxa de qualquer quarto que não apareceu na lista do primeiro cliente. Consequentemente, cada vez que o primeiro cliente gera uma lista de quartos disponíveis para um determinado intervalo de datas, a lista produzida pode conter quartos ou taxas de quartos que não foram vistos antes. Figura 2 ilustra esse comportamento.

Figura 2. Exemplo de como o nível de isolamento estabilidade de leitura pode afetar o comportamento do aplicativo
Exemplo de como o nível de isolamento estabilidade de leitura pode afetar o comportamento do aplicativo

O nível de isolamento de Estabilidade do Cursor

O nível de isolamento estabilidade do cursor é ainda menos restritivo que o nível estabilidade de leitura, devido à forma como ele isola os efeitos de transações simultâneas. Quando se usa esse nível de isolamento, a ocorrência de atualizações perdidas e leituras sujas não é possível, mas leituras não repetidas e fantasmas podem ser observados. Isso acontece porque, na maioria dos casos, quando se usa o nível de isolamento estabilidade do cursor, somente a linha que está sendo referenciada pela transação em isolamento é bloqueada. (No momento em que um registro é recuperado a partir de um conjunto de dados de resultados, um ponteiro — conhecido como cursor— é posicionado na linha correspondente na tabela subjacente — e essa é a linha que é bloqueada. Esse bloqueio permanecerá em vigor até que o cursor seja reposicionado — na maioria das vezes, por uma operação de FETCH ou — até que a transação proprietária seja finalizada). Já que somente um bloqueio no nível da linha é adquirido, o nível de isolamento estabilidade do cursor fornece o grau mais alto de simultaneidade disponível. Consequentemente, o DB2 usa esse nível de isolamento por padrão.

Quando uma transação que usa o nível de isolamento estabilidade do cursor recupera uma linha da tabela (por meio do cursor), nenhuma outra transação pode atualizar ou excluir essa linha enquanto o cursor estiver posicionado nela. As outras transações podem incluir novas linhas na tabela e realizar operações de atualização e exclusão nas linhas posicionadas nos dois lados do cursor (linha bloqueada) — desde que a linha bloqueada não tenha sido acessada por meio de um índice. Uma vez adquirido, o bloqueio permanece em vigor até que o cursor seja reposicionado ou a transação proprietária seja finalizada. (Se o cursor é reposicionado, na maioria dos casos, o bloqueio mantido na linha atual é liberado e um novo bloqueio é adquirido na linha para a qual o cursor foi movido). Se a transação em isolamento modifica qualquer linha que ele recupera, nenhuma outra transação pode atualizar ou excluir essa linha até que a transação proprietária seja finalizada — inclusive se o cursor for movido posteriormente da linha modificada.

Quando se usa o nível de isolamento estabilidade do cursor, se a mesma consulta é executada duas vezes ou mais dentro da mesma transação, os resultados produzidos podem variar. Além disso, as mudanças feitas em outras linhas por outras transações não serão vistas até que essas mudanças tenham sido confirmadas. (Isso também vale para as transações que executam sob os níveis de isolamento leitura repetida e estabilidade de leitura).

Mais uma vez, vamos examinar como esse nível de isolamento afeta o funcionamento do nosso aplicativo de reservas do motel. Agora, quando um cliente varre um banco de dados procurando uma lista de quartos disponíveis em um determinado intervalo de datas e, em seguida, visualiza informações sobre o primeiro quarto da lista, outros clientes podem fazer ou cancelar reservas de qualquer quarto exceto o quarto que o primeiro cliente está vendo no momento (para o intervalo de dados especificado). Da mesma forma, o seu gerente pode alterar a taxa de qualquer quarto, com exceção daquele que o cliente está vendo no momento (novamente, para o intervalo de datas especificado). Quando o primeiro cliente visualiza informações sobre o próximo quarto da lista, outros clientes — e também o gerente — podem fazer alterações no registro do quarto que o primeiro cliente estava vendo (desde que ele não tenha reservado o quarto). Entretanto, nenhum deles (nem o gerente nem outros clientes) pode alterar o registro do quarto que o primeiro cliente está vendo no momento. Figura 3 ilustra esse comportamento.

Figura 3. Exemplo de como o nível de isolamento estabilidade do cursor pode afetar o comportamento do aplicativo
Exemplo de como o nível de isolamento estabilidade do cursor pode afetar o comportamento do aplicativo

O nível de isolamento de Leitura Não Confirmada

O nível de isolamento leitura não confirmada é o menos restritivo de todos os níveis disponíveis. Nesse nível de isolamento, os efeitos de uma transação normalmente não são isolados dos efeitos das transações que estão executando no momento. Consequentemente podem ocorrer — e ocorrem frequentemente — leituras sujas, leituras não repetidas e fantasmas. Isso acontece porque, quando se usa o nível de isolamento leitura não confirmada, as linhas recuperadas por uma transação só são bloqueadas se a transação tenta modificar os dados armazenados nas linhas ou se outra transação tenta descartar ou alterar a tabela subjacente a partir da qual as linhas foram recuperadas. Já que as linhas geralmente permanecem desbloqueadas quando se usa o nível de isolamento leitura não confirmada, esse nível normalmente é usado quando as transações acessam tabelas e visualizações somente leitura ou quando são executadas transações nas quais a recuperação de dados não confirmados não produz efeitos adversos.

Como o nome indica, as transações executadas sob o nível de isolamento leitura não confirmada podem ver as alterações feitas por outras transações nas linhas antes da confirmação dessas mudanças. No entanto, isso não acontece quando outras transações criam tabelas, índices e visualizações. Nessas situações, a transação que cria o objeto (ou os objetos) deve estar confirmada para que ele possa ser visto ou acessado pelas transações que executam sob o nível de isolamento leitura não confirmada. Isso também acontece quando tabelas, índices ou visualizações já existentes são excluídas (eliminadas). As transações que executam sob o nível de isolamento leitura não confirmada não saberão que esses objetos não existem mais até que a transação que os eliminou seja confirmada. (É importante ressaltar que, quando uma transação que executa sob esse nível de isolamento usa um cursor passível de atualização, a transação se comporta como se estivesse executando sob o nível de isolamento estabilidade do cursor, e as restrições desse nível são aplicadas).

Então, como o nível de isolamento leitura não confirmada afeta o seu aplicativo de reservas do motel? Agora, quando um cliente varre o banco de dados para obter uma lista de quartos disponíveis para um determinado intervalo de datas, outros clientes podem fazer ou cancelar reservas de qualquer quarto do motel, inclusive o quarto que o primeiro cliente está vendo no momento. Da mesma forma, o seu gerente pode alterar as taxas de qualquer quarto do motel (em qualquer intervalo de datas). (Infelizmente, o primeiro cliente pode ser impedido de reservar um quarto que aparentemente está ocupado, mas, na verdade, está livre. Também pode reservar um quarto a uma taxa, mas depois ver que ela foi alterada). Figura 4 ilustra esse comportamento.

Figura 4. Exemplo de como o nível de isolamento leitura não confirmada pode afetar o comportamento do aplicativo
Exemplo de como o nível de isolamento leitura não confirmada pode afetar o comportamento do aplicativo

Especificando o nível de isolamento a ser usado

Embora os níveis de isolamento controlem a simultaneidade no âmbito da transação, na verdade eles são configurados no âmbito do aplicativo (ou, em alguns casos, no da instrução SQL). Portanto, na maioria dos casos, o nível de isolamento usado por um aplicativo específico é aplicado a todas as transações executadas por ele. (É importante ressaltar que o aplicativo pode ser construído em várias partes, e cada parte pode ter um nível de isolamento diferente — nesse caso, o nível de isolamento usado por uma parte determina o nível de isolamento que será usado por todas as transações dentro dessa parte).

Em aplicativos de SQL integrada, o nível de isolamento a ser usado é especificado no momento da pré-compilação ou quando o aplicativo é ligado a um banco de dados (caso se use a ligação adiada). Nesse caso, o nível de isolamento é configurado por meio da opção ISOLATION [RR | RS | CS | UR] dos comandos PRECOMPILE e BIND .

Em aplicativos de interface do nível de chamada (CLI) e Open Database Connectivity (ODBC), o nível de isolamento é configurado no tempo de execução do aplicativo chamando a função SQLSetConnectAttr() com o atributo de conexão SQL_ATTR_TXN_ISOLATION especificado. (Como alternativa, é possível configurar o nível de isolamento a ser utilizado em aplicativos de CLI/ODBC designando um valor para a palavra-chave TXNISOLATION no arquivo de configuração db2cli.ini. Entretanto, essa abordagem não fornece a flexibilidade de usar níveis de isolamento diferentes para transações individuais que a primeira abordagem oferece).

Finalmente, em aplicativos de Java™ Database Connectivity (JDBC) e SQLJ, o nível de isolamento é configurado no tempo de execução do aplicativo chamando o método setTransactionIsolation() que reside na interface de conexão java.sql do DB2.

Foi mencionado que, quando o nível de isolamento de um determinado aplicativo não é configurado explicitamente (usando um dos métodos descritos), o nível de isolamento estabilidade do cursor é usado por padrão. Isso vale para comandos do DB2, instruções SQL e scripts executados a partir do processador de linha de comando (CLP) do DB2 e para SQL integrada e aplicativos de CLI/ODBC, JDBC e SQLJ. Portanto, da mesma forma que também é possível controlar o nível de isolamento usado por um aplicativo, é possível controlar o nível de isolamento que é usado quando as operações são executadas a partir do processador de linha de comando do DB2. Nesse caso, é possível configurar o nível de isolamento executando o comando CHANGE ISOLATION LEVEL logo antes do estabelecimento de uma conexão ao banco de dados.

No DB2 8.1 e versões posteriores, é possível substituir o nível de isolamento padrão (ou o nível de isolamento especificado para um aplicativo específico) ao executar consultas individuais. Isso é feito anexando a cláusula WITH [RR | RS | CS | UR] a uma instrução SELECT— essa cláusula indica que uma instrução SELECT deve ser executada usando o nível de isolamento de leitura repetida (RR), estabilidade de leitura (RS), estabilidade do cursor CS) ou leitura não confirmada (UR). Portanto, se você quisesse obter uma lista de todos os funcionários que trabalham em um departamento específico e executar a consulta que produzirá essa lista sob o nível de isolamento de leitura repetida, poderia simplesmente executar uma instrução SELECT que é mais ou menos assim:

SELECT lastname FROM employee WHERE workdept = 'E11' 
   WITH RR

Portanto, se você tem um aplicativo que precisa executar sob um nível de isolamento menos restritivo na maior parte do tempo (para suportar o máximo de simultaneidade), mas contém duas consultas ou mais que não podem ter certos tipos de fenômenos (leituras sujas, leituras não repetidas e/ou fantasmas), é possível usar uma combinação de níveis de isolamento no âmbito do aplicativo e da instrução SQL para alcançar o seu objetivo.

Bloqueios

O aspecto que todos os níveis de isolamento têm em comum é o fato de adquirirem um bloqueio ou mais. O que é um bloqueio? O bloqueio é um mecanismo usado para associar um recurso de dados a uma única transação, com o objetivo de controlar como as outras transações interagem com esse recurso enquanto ele está associado à transação que o bloqueou. (Diz-se que a transação que tem um recurso de dados associado "mantém" o bloqueio ou é a "proprietária" dele). Basicamente, os bloqueios de um banco de dados têm o mesmo objetivo de um cadeado usado em uma casa ou carro: eles determinam quem pode (ou não) ter acesso — nesse caso, a um recurso específico — que pode ser um espaço de tabela, tabela, linha ou mais. O DB2 impõe bloqueios para proibir que outras transações façam modificações de dados que possam prejudicar a transação "proprietária". Quando uma transação proprietária é finalizada (por uma operação de confirmação ou retrocesso), quaisquer mudanças feitas no recurso que foi bloqueado se tornam permanentes ou são retrocedidas, e todos os bloqueios no recurso adquirido em nome da transação proprietária são liberados. Uma vez desbloqueado, o recurso pode ser bloqueado e manipulado por outra transação ativa. Figura 5 ilustra os princípios do bloqueio de transações/recursos.

Figura 5. Como o DB2 impede o acesso simultâneo não controlado a um recurso por meio de bloqueios
Como o DB2 impede o acesso simultâneo não controlado a um recurso por meio de bloqueios

Atributos e estados de bloqueios

Os bloqueios usados pelo DB2 têm os seguintes atributos básicos:

  • Objeto— Identifica o recurso de dados que está sendo bloqueado. O DB2 adquire bloqueios implicitamente sobre os recurso de dados (especificamente, espaços de tabela, tabelas e linhas) sempre que eles são necessários.
  • Tamanho— Identifica o tamanho físico do recurso de dados que está sendo bloqueado. (Em outras palavras, quantos dados estão sendo bloqueados). Um bloqueio nem sempre precisa controlar um recurso de dados inteiro. Por exemplo, em vez de dar a uma transação o controle exclusivo sobre uma tabela inteira, o DB2 pode optar por dar a um aplicativo o controle exclusivo apenas sobre uma ou duas linhas específicas da tabela.
  • Duração— Identifica o tempo de bloqueio. O nível de isolamento utilizado tem um impacto significativo na duração do bloqueio. Por exemplo, é provável que o bloqueio adquirido para uma transação de leitura repetida que acessa 500 linhas tenha uma longa duração caso todas as linhas tenham que ser atualizadas. Entretanto, é provável que o bloqueio adquirido para uma transação de estabilidade do cursor tenha uma duração muito mais curta.
  • Estado (ou modo)— Identifica o tipo de acesso permitido para o proprietário do bloqueio e outros usuários simultâneos do recurso de dados bloqueado. Tablela 2 mostra os vários estados de bloqueio disponíveis (juntamente com os seus efeitos), para aumentar o controle sobre os recursos que estão disponíveis no DB2 10.1.
Tablela 2. Estados (modos) de bloqueio disponíveis no DB2 10.1
Estado de (modo) bloqueioPlataformaObjetos aplicáveisAcesso do proprietário do bloqueioAcesso simultâneo a transações
Intent None (IN)DB2 para Linux, UNIX e WindowsEspaços de tabela, bloqueios, tabelas e partições de dadosO proprietário do bloqueio pode ler todos os dados, inclusive os não confirmados, armazenados no recurso bloqueado, mas não pode modificar os dados armazenados no recurso. Os bloqueios Intent None normalmente são adquiridos para transações de somente leitura que não têm a intenção de modificar dados (portanto, não serão adquiridos bloqueios adicionais em nome da transação).Outras transações podem ler e modificar dados armazenados no recurso bloqueado, mas não podem excluir dados armazenados no recurso.
Intent Share (IS)DB2 para Linux, UNIX e Windows; DB2 para z/OSEspaços de tabela, bloqueios, tabelas e partições de dadosO proprietário do bloqueio pode ler todos os dados (exceto os não confirmados) armazenados no recurso bloqueado, mas não pode modificar os dados armazenados no recurso. Normalmente, os bloqueios Intent Share são adquiridos para transações que não têm a intenção de modificar dados (ou seja, transações que não contêm instruções SELECT FOR UPDATE, UPDATE WHERE ou INSERT ).Outras transações podem ler e modificar dados armazenados no recurso bloqueado.
Intent Exclusive (IX)DB2 para Linux, UNIX e Windows; DB2 para z/OSEspaços de tabela, bloqueios, tabelas e partições de dadosO proprietário do bloqueio pode ler e modificar dados armazenados no recurso bloqueado. Os bloqueios Intent Exclusive normalmente são adquiridos para transações que têm a intenção de modificar dados (ou seja, transações que contêm instruções SELECT FOR UPDATE, UPDATE WHERE ou INSERT ).Outras transações podem ler e modificar dados armazenados no recurso bloqueado.
Scan Share (NS)DB2 para Linux, UNIX e WindowsLinhasO proprietário do bloqueio pode ler todos os dados (exceto os não confirmados) armazenados no recurso bloqueado, mas não pode modificar os dados armazenados no recurso. Os bloqueios Next Key Share normalmente são adquiridos no lugar de um bloqueio Share (S) para transações que estão executando sob o nível de isolamento estabilidade de leitura (RS) ou estabilidade do cursor (CS).Outras transações podem ler todos os dados (exceto os não confirmados) armazenados no recurso bloqueado, mas não podem modificar os dados armazenados no recurso.
Next Key Weak Exclusive (NW)DB2 para Linux, UNIX e WindowsLinhasO proprietário do bloqueio pode ler todos os dados (exceto os não confirmados) armazenados no recurso bloqueado, mas não pode modificar os dados armazenados no recurso. Os bloqueios Next Key Weak Exclusive normalmente são adquiridos sobre a linha seguinte disponível da tabela sempre que uma linha é inserida em um índice. Isso só ocorre se a linha seguinte está bloqueada no momento por uma varredura realizada sob o nível de isolamento de leitura repetida (RR).Outras transações podem ler todos os dados (exceto os não confirmados) armazenados no recurso bloqueado, mas não podem modificar os dados armazenados no recurso.
Share (S)DB2 para Linux, UNIX e Windows; DB2 para z/OSBloqueios, tabelas, linhas, partições de dadosO proprietário do bloqueio pode ler todos os dados (exceto os não confirmados) armazenados no recurso bloqueado, mas não pode modificar os dados armazenados no recurso. Normalmente, os bloqueios compartilhados são adquiridos para transações que não têm a intenção de modificar dados que estão executando sob o nível de isolamento de leitura repetida (RR). (As transações que contêm instruções SELECT FOR UPDATE, UPDATE WHERE ou INSERT têm a intenção de modificar dados). Outras transações podem ler todos os dados (exceto os não confirmados) armazenados no recurso bloqueado, mas não podem modificar os dados armazenados no recurso.
Share With Intent Exclusive (SIX)DB2 para Linux, UNIX e Windows; DB2 para z/OSBloqueios, tabelas, partições de dadosO proprietário do bloqueio pode ler e modificar dados armazenados no recurso bloqueado. Os bloqueios Share With Intent Exclusive normalmente são adquiridos quando uma transação que mantém um bloqueio de compartilhamento (S) em um recurso tenta adquirir um bloqueio Intent Exclusive (IX) no mesmo recurso (ou vice-versa).Outras transações podem ler todos os dados (exceto os não confirmados) armazenados no recurso bloqueado, mas não podem modificar os dados armazenados no recurso.
Update (U)DB2 para Linux, UNIX e Windows; DB2 para z/OSBloqueios, tabelas, linhas, partições de dadosO proprietário do bloqueio pode modificar todos os dados (exceto os dados não confirmados) armazenados no recurso bloqueado, mas não pode ler os dados armazenados no recurso. Normalmente, os bloqueios de atualização são adquiridos para transações que modificam dados com instruções INSERT, UPDATE ou DELETE .Outras transações podem ler todos os dados (exceto os não confirmados) armazenados no recurso bloqueado, mas não podem modificar os dados armazenados no recurso.
Exclusive (X)DB2 para Linux, UNIX e Windows; DB2 para z/OSBloqueios, tabelas, linhas, partições de dados, buffer poolsO proprietário do bloqueio pode ler e modificar os dados armazenados no recurso bloqueado. Normalmente, os bloqueios restritos são adquiridos para as transações que recuperam dados com instruções SELECT e, em seguida, modificam os dados com instruções INSERT, UPDATE ou DELETE . (As transações que somente recuperam dados com instruções SELECT não precisam de um bloqueio restrito).As transações que usam o nível de isolamento leitura não confirmada podem ler todos os dados, inclusive dados não confirmados, armazenados no recurso bloqueado, mas não podem modificar os dados armazenados no recurso. Nenhuma outra transação pode ler nem modificar os dados armazenados no recurso bloqueado.
Super Exclusive (Z)DB2 para Linux, UNIX e WindowsEspaços de tabela, bloqueios, tabelas e partições de dadosO proprietário do bloqueio pode ler e modificar dados armazenados no recurso bloqueado. Os bloqueios Super Exclusive normalmente são adquiridos em uma tabela sempre que o proprietário do bloqueio tenta alterar a tabela ou eliminá-la, criar um índice para a tabela, eliminar um índice que já foi definido para a tabela ou reorganizar o conteúdo da tabela (enquanto a tabela está offline) executando o utilitário REORG .As outras transações não podem ler nem modificar os dados armazenados no recurso bloqueado.
Adaptado da Tabela 1, encontrada sob Lock Attributes no Centro de Informações do IBM DB2 10.1 para Linux, UNIX e Windows. (http://publib.boulder.ibm.com/infocenter/db2luw/v10r1/topic/com.ibm.db2.luw.admin.perf.doc/doc/c0005270.html)

Como bloqueios são adquiridos

Exceto nas ocasiões em que o nível de isolamento leitura não confirmada é usado, a transação nunca precisa solicitar um bloqueio explicitamente. Isso acontece porque o DB2 adquire bloqueios automaticamente à medida que eles se tornam necessários. Depois de adquiridos, esses bloqueios permanecem sob o controle do DB2 até que ele seja liberado. Por padrão, o DB2 sempre tenta adquirir bloqueios no nível da linha. Entretanto, é possível controlar se haverá uma tentativa de adquirir bloqueios no nível da linha ou da tabela em um recurso de tabela específico executando uma forma especial da instrução SQL ALTER TABLE . A sintaxe dessa forma da instrução ALTER TABLE é ALTER TABLE [TableName,] LOCKSIZE [ROW | TABLE] , onde TableName identifica o nome de uma tabela já existente na qual o nível de bloqueio que todas as transações devem usar ao acessá-la é especificado.

OBSERVAÇÃO: Essa forma da instrução ALTER TABLE só está disponível no DB2 para Linux, UNIX e Windows. Não pode ser usada com o DB2 para z/OS.

Por exemplo, se a instrução SQL ALTER TABLE employee LOCKSIZE ROW for executada, o DB2 adquirirá automaticamente bloqueios de linha para todas as transações que acessarem uma tabela chamada EMPLOYEE. (Esse é o comportamento padrão). Se, em vez disso, a instrução SQL a seguir é executada: ALTER TABLE employee LOCKSIZE TABLE. o DB2 tentará adquirir bloqueios no nível da tabela para todas as transações que acessam a tabela EMPLOYEE.

Entretanto, e se você não quer que todas as transações que trabalham com uma determinada tabela adquiram bloqueios no nível da tabela? E se, em vez disso, você quer que uma ou duas transações específicas adquiram bloqueios no nível da tabela e todas as outras transações adquiram bloqueios de linha ao trabalhar com essa tabela? Nesse caso, é possível simplesmente deixar o comportamento padrão de bloqueio como está (para que se use o bloqueio no nível da linha) e usar a instrução LOCK TABLE para adquirir um bloqueio no nível da tabela para as transações individuais desejadas. A sintaxe da instrução LOCK TABLE é LOCK TABLE [TableName,] IN [SHARE | EXCLUSIVE] MODE onde: TableName identifica, pelo nome, a tabela a ser bloqueada.

Como é possível ver, a instrução LOCK TABLE permite que uma transação adquira um bloqueio no nível da tabela em uma tabela específica de um de dois modos: SHARE ou EXCLUSIVE. Se uma tabela é bloqueada no modo SHARE , é adquirido um bloqueio de compartilhamento (S) no nível da tabela em nome da transação solicitante e as outras transações simultâneas podem ler — mas não alterar — os dados armazenados na tabela bloqueada. Por outro lado, se uma tabela é bloqueada no modo EXCLUSIVE , um bloqueio Exclusive (X) no nível da tabela, e as outras transações simultâneas não podem realizar nenhum tipo de operação na tabela bloqueada.

Por exemplo, se a instrução SQL LOCK TABLE employee IN SHARE MODE é executada, um bloqueio Share (S) no nível da tabela é adquirido em uma tabela chamada EMPLOYEE em nome da transação atual (desde que nenhuma outra transação mantenha um bloqueio nessa tabela), e qualquer outra transação que execute simultaneamente poderá ler — mas não alterar — os dados armazenados na tabela EMPLOYEE. Por outro lado, se a seguinte instrução SQL é executada, LOCK TABLE employee IN EXCLUSIVE MODE, é adquirido um bloqueio Exclusive (X) no nível da tabela para a tabela EMPLOYEE, e nenhuma outra transação poderá ler nem modificar os dados armazenados nessa tabela até que a transação que executou a instrução LOCK TABLE seja confirmada ou retrocedida.

Quando se trata de decidir entre o uso de bloqueios de linha ou de tabela, é importante ter em mente que, sempre que uma transação mantém um bloqueio em um recurso específico, outras transações podem ter o acesso negado a esse recurso até que a transação proprietária seja finalizada. Portanto, geralmente os bloqueios no nível da linha são melhores que os bloqueios de tabela, já que restringem o acesso a um recurso muito menor. No entanto, como cada bloqueio adquirido requer um certo espaço de armazenamento (para manter) e um certo tempo de processamento (para gerenciar), geralmente a sobrecarga é muito menor quando se usa um único bloqueio de tabela em vez de vários bloqueios de linha.

Até certo ponto, a instrução LOCK TABLE (e, no DB2 para Linux, UNIX e Windows, a instrução ALTER TABLE ) pode ser usada para controlar a granularidade de bloqueio (ou seja, se é usado o bloqueio de linha ou de tabela) no nível globalALTER TABLE) e no nível da transação (LOCK TABLE). Portanto, quando é mais recomendável controlar a granularidade no nível global e não no nível da transação? Depende.

Suponha que você tenha uma tabela de consulta somente leitura que várias transações simultâneas precisam acessar. O ato de forçar o DB2 a adquirir bloqueios Share (S) de tabela globalmente em nome de cada transação que tenta acessar essa tabela pode melhorar o desempenho, já que a sobrecarga de bloqueio necessária seria bastante reduzida. Por outro lado, se você tem uma tabela que deve ser acessada frequentemente por transações somente leitura e periodicamente por uma única transação que faz algum tipo de manutenção, forçar o DB2 a adquirir somente um Exclusive (X) de tabela só para a transação de manutenção provavelmente faz mais sentido do que forçá-lo a adquirir um bloqueio Exclusive (X) de tabela para todas as transações que tentam acessar a tabela. Nesse caso, se um bloqueio Exclusive (X) de tabela é adquirido no nível da instância, as transações somente leitura só são bloqueadas da tabela quando a transação de manutenção é executada; em todas as outras situações, essas transações podem acessar a tabela simultaneamente sem precisar de muita sobrecarga de bloqueio.


Anulação do bloqueio e semântica atualmente confirmada

Anulação do bloqueio

Antes do DB2 9.7, se o nível de isolamento estabilidade do cursor fosse usado e uma linha fosse bloqueada em nome de uma transação, o DB2 bloquearia as tentativas de outras transações que executam simultaneamente de modificar a linha bloqueada. Além disso, se a linha bloqueada fosse alterada de qualquer forma pela transação que mantém o bloqueio, as outras instruções SQL em transações simultâneas não podiam acessar a linha (a menos que estivessem executando sob o nível de isolamento leitura não confirmada) até que a transação fosse finalizada. (Em outras palavras, os gravadores bloqueariam os leitores e, em algumas situações, os leitores poderiam bloquear os gravadores). Em qualquer um dos casos, as transações simultâneas que precisavam acessar uma linha bloqueada eram forçadas a aguardar a liberação do bloqueio para poder continuar o processamento. Isso, por outro lado, provocava a ocorrência de comportamentos não desejados.

No DB2 9.5, foram introduzidas várias técnicas de anulação de bloqueio para ajudar a eliminar parte da sobrecarga de bloqueio que era necessária para o nível de isolamento estabilidade do cursor. Basicamente, essas técnicas permitem executar operações de varredura sem bloquear as linhas quando se sabe que os dados e/ou as páginas que estão sendo acessadas foram confirmadas. Por exemplo, considere a consulta a seguir: SELECT COUNT(*) FROM sales.

Antes do DB2 9.5, quando uma consulta desse tipo era executada, a primeira linha da tabela especificada era bloqueada, fazia-se uma contagem e o bloqueio era liberado. Em seguida, a segunda linha da tabela era bloqueada, a consulta era atualizada e o bloqueio era liberado. E isso continuava até que todas as linhas da tabela fossem contadas. No DB2 9.5 e versões posteriores, a mesma consulta varre a tabela especificada e conta as linhas, mas os bloqueios intermitentes não são mais adquiridos nem liberados — desde que o DB2 possa determinar que as linhas foram confirmadas sem a necessidade de adquirir bloqueios. Basicamente, a anulação de bloqueio permite que o DB2 determine se os dados foram confirmados e, caso isso tenha acontecido, os bloqueios não são adquiridos. No DB2 9.7 e no 10.1, a anulação de bloqueio funciona para qualquer instrução SQL somente leitura executada sob o nível de isolamento estabilidade do cursor usando o bloqueio do cursor. (Bloqueio do cursor é uma técnica que reduz a sobrecarga fazendo o DB2 recuperar um bloco de linhas, e não só uma linha, em uma operação).

Semântica atualmente confirmada

No DB2 9.7, foi fornecida uma nova implementação do nível de isolamento estabilidade do cursor. Ela incorpora a semântica atualmente confirmada (CC) para impedir que os gravadores bloqueiem os leitores. A intenção é fornecer um nível de isolamento estabilidade do cursor que evita as esperas de bloqueio sem violar os padrões ANSI sobre a semântica do nível de isolamento estabilidade do cursor. (Nas versões anteriores do DB2 para Linux, UNIX e Windows, as seguintes variáveis de registro podiam ser usadas para atrasar ou evitar a aquisição de bloqueios em algumas circunstâncias:

  • DB2_SKIPINSERTED— Permitir que as varreduras em estabilidade do cursor/estabilidade de leitura ignorem as linhas inseridas não confirmadas.
  • DB2_SKIPDELETED— Permitir que as varreduras em estabilidade do cursor/estabilidade de leitura ignorem as linhas e chaves de índice excluídas e não confirmadas.
  • DB2_EVALUNCOMMITTED— Permitir que as varreduras de estabilidade do cursor/estabilidade de leitura apliquem e realizem avaliação de predicados de consulta em dados não confirmados; permitir também que as varreduras ignorem as linhas excluídas não confirmadas. De fato, as varreduras são tratadas como uma operação de leitura não confirmada até que se localize uma linha qualificada; nesse momento, é possível que o DB2 tenha que adquirir um bloqueio para garantir que só dados confirmados sejam processados ou retornados.

Entretanto, o uso dessas variáveis de registro provoca uma violação do padrão ANSI para a semântica do nível de isolamento estabilidade do cursor).

O uso das técnicas de anulação de bloqueio introduzidas no DB2 9.5, uma transação de somente leitura que opera sob a semântica atualmente confirmada, não relizará um bloqueio desde que o DB2 possa determinar que os dados necessários foram confirmados. (As transações que executam operações de leitura e gravação evitam as esperas de bloqueio em inserções não confirmadas, e as transações que realizam operações somente leitura acabam trocando uma espera de bloqueio por uma leitura de log quando encontram atualizações/exclusões não confirmadas de transações simultâneas). Se o DB2 não consegue determinar se uma linha foi confirmada, ele tenta adquirir um bloqueio na linha em questão em nome da transação — se é possível adquirir um bloqueio, o processamento continua usando o comportamento tradicional do nível de isolamento estabilidade do cursor. Se não é possível adquirir um bloqueio (porque outra transação mantém um bloqueio restrito na linha) o DB2 examina o bloqueio que é mantido por outra transação para obter informações sobre a linha que contém os dados necessários. Cada linha pode conter um (e somente um) dos seguintes:

  • Sem informações— Indica que a linha está bloqueada, mas não foi feito nada nela (não há mudanças não confirmadas em andamento).
  • Um identificador de inserção não confirmada— Indica que a linha foi inserida recentemente e ainda não foi confirmada.
  • Informação de log— Indica que a linhas contém dados não confirmados. Nesse caso, a informação de log identifica o registro de log que corresponde à primeira vez que a linha foi modificada pela transação que mantém o bloqueio na linha no momento.

Se o bloqueio não contém nenhuma informação, a linha é tratada como se o bloqueio desejado tivesse sido adquirido. Se o bloqueio contém um identificador de inserção não confirmada, a linha é ignorada, já que esse identificador representa uma linha que ainda não foi confirmada. Se o log contém alguma informação de log, ela é usada para retornar a versão atualmente confirmada da linha (ou seja, a linha como ela era antes do início das mudanças) a partir de um registro de log armazenado no buffer do log ou em um arquivo de log de transações. (O DB2 usa o número de sequência do log, LSN, para acessar diretamente o registro de log apropriado — consulte a barra lateral).

Como o DB2 pode saber se os dados foram confirmados

Todas as linhas de dados e entradas de índice têm um byte de "sinalizadores" que contém um bit de "Possibly UNCommitted" (possivelmente não confirmado) ou PUNC. Se o bit PUNC não é configurado, há a certeza de que a linha de dados/entrada de índice foi confirmada; do contrário, o status de confirmação não é conhecido.

As páginas contêm um "pageLSN" que identifica o LSN do registro de log que corresponde à última modificação feita na página. Se o pageLSN é mais antigo que o commitLSN do banco de dados ou o readLSN da tabela, há a certeza de que a linha/chave foi confirmada; do contrário, status de confirmação é desconhecido.

É importante ressaltar que a semântica atualmente confirmada pode se aplicar a instruções SQL executadas sob os níveis de isolamento estabilidade de leitura (RS) e estabilidade do cursor. No nível de isolamento estabilidade de leitura, a semântica atualmente confirmada somente fornece o comportamento DB2_SKIPINSERTED que é a capacidade de não incorrer mais em esperas de bloqueio para linhas inseridas não confirmadas.

Figura 6 ilustra como uma instrução SELECT que executa o nível de isolamento estabilidade do cursor com a semântica atualmente confirmada habilitada recupera registros quando outra transação está alterando os registros simultaneamente. Nesse exemplo, a Transação 1 executou três instruções DML, que fizeram com que a informação de log fosse gravada no buffer do log e que um identificador de inserção não confirmada fosse gravado na lista de bloqueios da tabela SALES_REP. Quando a transação 2 consultou a tabela SALES_REP, a semântica atualmente confirmada permitiu que os dados das linhas bloqueadas fossem lidos a partir de registros de log que continham informações sobre transações confirmadas anteriormente; o registro da inserção não confirmada não foi retornado pela consulta.

Figura 6. Exemplo de como uma consulta executada sob o nível de isolamento estabilidade do cursor com a semântica atualmente confirmada habilitada recupera os registros
Exemplo de como uma consulta executada sob o nível de isolamento estabilidade do cursor com a semântica atualmente confirmada habilitada recupera os registros

Habilitando o comportamento da semântica atualmente confirmada

Por padrão, a semântica atualmente confirmada é ativada em bancos de dados novos criados com o DB2 9.7 e versões posteriores. Os bancos de dados já existentes atualizados para o DB2 9.7 ou posterior podem aproveitar a semântica atualmente confirmada designando o valor ON ou o valor AVAILABLE ao parâmetro de configuração de banco de dados cur_commit do banco de dados que foi convertido. Se o parâmetro de configuração de banco de dados cur_commit é configurado como ON, a semântica atualmente confirmada é aplicada a todo o banco de dados nos níveis de isolamento estabilidade de leitura e estabilidade do cursor. Se o parâmetro de configuração de banco de dados cur_commit é configurado como AVAILABLE , o DB2 armazena as informações adequadas em bloqueios e realiza a sobrecarga extra de criação de log necessária (para garantir que os dados registrados contenham a versão completa não confirmada da linha que está sendo alterada) para suportar a semântica atualmente confirmada. É necessário ativar o comportamento da semântica atualmente confirmada em cada aplicativo. Isso é feito ligando um aplicativo de SQL integrada ao banco de dados usando a opção CONCURRENTACCESSRESOLUTION USE CURRENTLY COMMITTED ou especificando o atributo de conexão SQL_ATTR_CONCURRENT_ACCESS_RESOLUTION com aplicativos de CLI/ODBC e Java.

É importante ressaltar que o uso da semântica atualmente confirmada provoca um aumento no espaço de log necessário para as operações de atualização em tabelas que foram definidas como DATA CAPTURE NONE. Esse espaço adicional é usado para registrar a primeira atualização de uma linha de dados por uma transação; esses dados são usados para recuperar a imagem atualmente confirmada da linha.


Bloqueios e desempenho

Como o DB2 adquire bloqueios implicitamente à medida que eles se tornam necessários, com exceção do uso da instrução LOCK TABLE (e, no DB2 para Linux, UNIX e Windows, a instrução ALTER TABLE ) para forçar o DB2 a adquirir bloqueios de tabela, o bloqueio fica praticamente fora do seu controle. Há vários fatores que influenciam a forma como o bloqueio afeta o desempenho. Esses fatores incluem:

  • Compatibilidade de bloqueio
  • Conversão de bloqueio
  • Escalação de bloqueios
  • Esperas e tempos limite de bloqueio
  • Conflitos

O conhecimento desses fatores e a compreensão de como eles afetam o desempenho podem ajudar você a projetar aplicativos de banco de dados que funcionam bem em ambientes de banco de dados multiusuário.

Compatibilidade de bloqueio

Se o estado de um bloqueio mantido em um recurso de dados por uma transação permite que outra transação coloque outro bloqueio no mesmo recurso antes que o primeiro bloqueio seja liberado, os bloqueios são considerados compatíveis. E, sempre que uma transação mantém um bloqueio em um recurso de dados e outra transação tenta adquirir um bloqueio no mesmo recurso, o DB2 examina o estado de cada bloqueio e determina se eles são compatíveis. Tablela 3 contém uma matriz de compatibilidade de bloqueios que identifica quais bloqueios são compatíveis.

Tablela 3. Matriz de compatibilidade de bloqueios
Bloqueio solicitado pela segunda transação
Estado do bloqueioINISNSSIXSIXUXZNW
Bloqueio mantido pela primeira transaçãoINSimSimSimSimSimSimSimSimNãoSim
ISSimSimSimSimSimSimSimNãoNãoNão
NSSimSimSimSimNãoNãoSimNãoNãoSim
SSimSimSimSimNãoNãoSimNãoNãoNão
IXSimSimNãoNãoSimNãoNãoNãoNãoNão
SIXSimSimNãoNãoNãoNãoNãoNãoNãoNão
USimSimSimSimNãoNãoNãoNãoNãoNão
XSimNãoNãoNãoNãoNãoNãoNãoNãoNão
ZNãoNãoNãoNãoNãoNãoNãoNãoNãoNão
NWSimNãoSimNãoNãoNãoNãoNãoNãoNão
Sim — Os bloqueios são compatíveis. A solicitação de bloqueio é atendida imediatamente Não — Os bloqueios não são compatíveis. A transação solicitante precisa aguardar a liberação ou o tempo limite do bloqueio para atender a solicitação de bloqueio.
Estados de bloqueio: IN — Intent None IS — Intent Share NS — Scan Share S — Share IX — Intent Exclusive SIX — Share With Intent Exclusive U — Update X — Exclusive Z — Super Exclusive NW — Next Key Weak Exclusive
Adaptado da Tabela 1, encontrada sob Lock type compatibility no Centro de Informações do IBM DB2 10.1 para Linux, UNIX e Windows. (http://publib.boulder.ibm.com/infocenter/db2luw/v10r1/topic/com.ibm.db2.luw.admin.perf.doc/doc/r0005274.html)

Conversão/promoção de bloqueio

Se uma transação que mantém um bloqueio em um recurso precisa adquirir um bloqueio mais restritivo sobre ele, em vez de liberar o bloqueio antigo e adquirir um novo, o DB2 tenta alterar o estado do bloqueio para o estado mais restritivo que é necessário. A ação de alterar o estado de um bloqueio já existente é conhecida como conversão de bloqueio (DB2 para Linux, UNIX e Windows) ou promoção do bloqueio (DB2 para z/OS); a conversão/promoção do bloqueio ocorre porque a transação só pode manter um bloqueio em cada recurso. Figura 7 ilustra como a conversão/promoção de bloqueio funciona.

Figura 7. A conversão/promoção altera o bloqueio que está sendo mantido
A conversão/promoção altera o bloqueio que está sendo mantido

Na maioria dos casos, a conversão/promoção do bloqueio é realizada em bloqueios de linha, e o processo é razoavelmente objetivo. Por exemplo, se um bloqueio Update (U) é mantido e um bloqueio Exclusive (X) é necessário, o bloqueio Update (U) é convertido/promovido a Exclusive (X), mas isso nem sempre acontece quando se trata de bloqueios Share (S) e Intent Exclusive (IX). Já que nenhum dos bloqueios é considerado mais restritivo que o outro, se um bloqueio é mantido e o outro é solicitado, o bloqueio mantido é convertido/promovido para Share With Intent Exclusive (SIX). Em todos os outros bloqueios, o estado do bloqueio atual é alterado para o estado que está sendo solicitado — desde que o estado solicitado seja mais restritivo. (A conversão/promoção de bloqueio só ocorre se o bloqueio mantido pode aumentar a sua restrição). Depois que o bloqueio é convertido, ele permanece no nível mais alto que foi atingido até que a transação que mantém o bloqueio seja finalizada e o bloqueio seja liberado.

Escalação de bloqueios

Quando uma conexão ao banco de dados é estabelecida pela primeira vez, uma quantidade específica de memória é separada para conter uma estrutura que o DB2 usa para gerenciar bloqueios. É nessa estrutura, conhecida como lista de bloqueios, que os bloqueios mantidos por todas as transações ativas são armazenados após a aquisição. (A quantidade real de memória que é separada para a lista de bloqueios é controlada por meio do parâmetro de configuração de banco de dados locklist ).

Como a quantidade de memória disponível é limitada e essa memória deve ser compartilhada por todas as transações ativas, o DB2 impõe um limite na quantidade de espaço que cada transação pode consumir na lista de bloqueios. (Esse limite é controlado por meio do parâmetro de configuração de banco de dados maxlocks ). Para impedir que um agente de banco de dados (que atua em nome de uma transação) ultrapasse as suas limitações de espaço na lista de bloqueios, realiza-se um processo conhecido como escalação de bloqueios sempre que uma quantidade excessiva de bloqueios (independentemente do tipo) foi adquirida em nome de uma única transação. Durante a escalação de bloqueios, o espaço na lista de bloqueios é liberado ao substituir vários bloqueios de linha com um único bloqueio de tabela. Figura 8 ilustra como a escalação de bloqueios funciona.

Figura 8. A escalação de bloqueios substitui vários bloqueios de linha individuais por um único bloqueio de tabela
A escalação de bloqueios substitui vários bloqueios de linha individuais por um único bloqueio de tabela

Como a escalação de bloqueios funciona? Quando uma transação solicita um bloqueio e a lista de bloqueios do banco de dados está cheia, uma das tabelas associadas à transação que solicita o bloqueio é selecionada, um bloqueio de tabela é adquirido em nome da transação e todos os bloqueios de linha da tabela são liberados para abrir espaço na lista de bloqueios. Em seguida, o bloqueio de tabela é adicionado à lista de bloqueios e, se mesmo assim a lista de bloqueios não tem o espaço de armazenamento necessário para adquirir o bloqueio solicitado, outra tabela é selecionada é o processo é repetido até que se abra um espaço livre suficiente — somente nesse momento o bloqueio solicitado é adquirido (nesse ponto, a transação tem permissão para continuar). Se o espaço necessário na lista de bloqueios ainda está indisponível (após a escalação de todos os bloqueios de linha da transação), é gerado um erro, todas as mudanças feitas no banco de dados pela transação são retrocedidas e a transação é finalizada graciosamente.

OBSERVAÇÃO: O uso da instrução LOCK TABLE não impede a escalação normal do bloqueio, mas pode reduzir a sua frequência.

Esperas e tempos limite de bloqueio

Como vimos, sempre que uma transação mantém um bloqueio em um recurso específico, outras transações que estão executando simultaneamente podem ter o acesso negado ao recurso até que a transação que mantém o bloqueio seja finalizada (nesse caso, todos os bloqueios adquiridos em nome da transação sejam liberados). Consequentemente, na falta de algum tipo de mecanismo de tempo limite do bloqueio, a transação pode aguardar indefinidamente a liberação de um bloqueio mantido por outra transação. Infelizmente, se uma das transações for finalizada prematuramente por outro usuário ou aplicativo, a consistência de dados pode ser comprometida.

Para impedir que situações como essa aconteçam, um recurso importante conhecido como detecção do tempo limite do bloqueio foi incorporado ao DB2. Quando é utilizado, esse recurso impede que as transações aguardem indefinidamente a liberação de um bloqueio. Designando um valor ao parâmetro locktimeout no arquivo de configuração do banco de dados adequado, é possível controlar quando a detecção do tempo limite do bloqueio ocorre. Esse parâmetro especifica o período de tempo que qualquer transação aguarda para obter um bloqueio solicitado; se o bloqueio desejado não é adquirido dentro do período especificado, todas as mudanças feitas pela transação no banco de dados são retrocedidas e a transação é finalizada graciosamente.

OBSERVAÇÃO: por padrão, o parâmetro de configuração locktimeout é configurado como -1, ou seja, as transações aguardarão indefinidamente para adquirir os bloqueios necessários. Em muitos casos, esse valor padrão deve ser alterado. Além disso, os aplicativos devem ser escritos de forma a capturar qualquer código de retorno SQL de tempo limite (ou conflito) retornado pelo DB2 e reagir adequadamente.

Conflitos

Em muitos casos, o problema da espera indefinida por um bloqueio pode ser evitado usando a semântica atualmente confirmada e especificando um tempo limite do bloqueio. No entanto, não é isso o que acontece quando a contenção de bloqueio provoca uma situação conhecida como conflito. A melhor forma de ilustrar como um conflito pode ocorrer é um exemplo: suponha que a Transação 1 adquira um bloqueio Exclusive (X) na Tabela A, e a Transação 2 adquira um bloqueio Exclusive (X) na Tabela B. Agora, suponha que a Transação 1 tente adquirir um bloqueio Exclusive (X) na Tabela B, e a Transação 2 tente adquirir um bloqueio Exclusive (X) na Tabela A. Já vimos que o processamento das duas transações será suspenso até que a segunda solicitação de bloqueio seja atendida. Já que nenhuma solicitação de bloqueio pode ser atendida até que uma das transações proprietárias libere o bloqueio que mantém no momento (realizando uma operação de confirmação ou retrocesso) e nenhuma das transações pode realizar uma operação de confirmação ou retrocesso porque as duas estão aguardando para adquirir bloqueios, houve uma situação de conflito. Figura 9 ilustra esse cenário.

Figura 9. Conflito
Conflito

O conflito é denominado, de forma mais precisa, ciclo de conflito porque as transações envolvidas formam um círculo de estados de espera. Cada transação no ciclo aguarda a liberação de um bloqueio mantido por outra transação do círculo (consulte a Figura 9). Quando ocorre um ciclo de conflito, todas as transações envolvidas aguardarão indefinidamente a liberação de um bloqueio, a menos que um agente externo intervenha e quebre o ciclo. No DB2, esse agente é um processo de segundo plano conhecido como detector de conflito, cuja única responsabilidade é localizar e resolver quaisquer conflitos encontrados no subsistema de bloqueio.

Cada banco de dados tem seu próprio detector de conflito, que é ativado como parte do processo de inicialização de banco de dados. Uma vez ativado, o detector de conflito fica "adormecido" na maior parte do tempo, mas acorda em intervalos pré-configurados e examina o subsistema de bloqueio para determinar se há uma situação de conflito. Normalmente, o detector de conflito acorda, vê que não há conflitos no subsistema de bloqueio e volta ao estado suspenso. Se o detector de conflito detecta um ciclo de conflito, ele selecionada aleatoriamente uma das transações envolvidas para ser retrocedida e finalizada; a transação escolhida (conhecida como processo vítima) recebe um código de erro SQL, e todos os bloqueios que ela tinha adquirido são liberados. As transações restantes podem continuar porque o ciclo de conflito foi quebrado. É possível, mas improvável, que haja mais de um ciclo de conflito no subsistema de bloqueio de um banco de dados. Se há vários ciclos de conflito, o detector os localiza e finaliza uma das transações irregulares da mesma forma, até que todos os ciclos de conflito tenham sido quebrados. No final, o detector de conflito volta ao estado suspenso e retorna no próximo intervalo predefinido para examinar novamente o subsistema de bloqueio.

Embora a maioria dos ciclos de conflito envolva dois recursos ou mais, um tipo especial de conflito, conhecido como conflito de conversão, pode ocorrer em um recurso individual. Os conflitos de conversão ocorrem quando duas transações (ou mais) que já mantêm bloqueios compatíveis em um objeto solicitam bloqueios novos e incompatíveis no mesmo objeto. Isso normalmente ocorre quando duas transações simultâneas (ou mais) procuram linhas em uma tabela realizando uma varredura de índice e, em seguida, tentam modificar uma linha recuperada ou mais.


Conclusão

Um banco de dados pode se tornar inconsistente se um usuário se esquece de fazer todas as mudanças necessárias, se o sistema trava enquanto o usuário está fazendo mudanças ou se um aplicativo de banco de dados para prematuramente. A inconsistência também pode ocorrer quando vários usuários ou aplicativos tentam acessar o mesmo recurso de dados ao mesmo tempo. Por exemplo, um usuário pode ler as mudanças realizadas por outra pessoa antes que todas as tabelas tenham sido atualizadas adequadamente e realizar alguma ação inadequada com base nos valores de dados prematuros que foram lidos. Na tentativa de impedir a inconsistência de dados, particularmente em ambientes multiusuário, os seguintes mecanismos de suporte à consistência de dados foram incorporados ao design do DB2:

  • Transações
  • Níveis de isolamento
  • Bloqueios

Uma transação (também conhecida como uma unidade de trabalho) é uma sequência recuperável de uma ou mais operações SQL, agrupadas como uma única unidade, geralmente dentro de um processo de aplicativo. A inicialização e o término de uma transação definem pontos de consistência em um banco de dados; os efeitos de todas as operações SQL realizadas dentro de uma transação são aplicados ao banco de dados (confirmados) ou são totalmente desfeitos (retrocedidos). De qualquer forma, fica garantido que o banco de dados esteja em um estado consistente na conclusão de cada transação.

Os níveis de isolamento determinam como os dados acessados e/ou modificados por uma transação são "isolados" de outras transações que estão executando ao mesmo tempo. O DB2 reconhece e suporta os seguintes níveis de isolamento:

  • Leitura Repetida
  • Estabilidade de Leitura
  • Estabilidade do Cursor
  • Leitura Não Confirmada

O nível de isolamento de leitura repetida é o mais restritivo, mas reduz bastante a simultaneidade (o número de transações que podem acessar o mesmo recurso simultaneamente). O nível de isolamento leitura não confirmada, por outro lado, fornece o nível mais alto de simultaneidade, mas permite a ocorrência de leituras sujas, leituras não repetidas e fantasmas.

O bloqueio é um mecanismo usado para associar um recurso de dados a uma única transação, com o objetivo de controlar de que forma as outras transações interagem com o recurso enquanto ele está associado à transação que adquiriu o bloqueio. O DB2 oferece os tipos de bloqueio a seguir:

  • Intent None (IN)
  • Intent Share (IS)
  • Intent Exclusive (IX)
  • Scan Share (NS)
  • Next Key Weak Exclusive (NW)
  • Share (S)
  • Share With Intent Exclusive (SIX)
  • Update (U)
  • Exclusive (X)
  • Super Exclusive (Z)

Para manter a integridade de dados, o DB2 adquire bloqueios implicitamente, e todos os bloqueios adquiridos ficam sob o controle do DB2 Database Manager. É possível manter bloqueios em espaços de tabela, blocos, tabelas e linhas. Para otimizar com o objetivo de obter simultaneidade máxima, os bloqueios de linha geralmente são melhores que os bloqueios de tabela, porque limitam o acesso a um recurso muito menor. Já que cada bloqueio adquirido requer um certo espaço de armazenamento e tempo de processamento para ser gerenciado, a aquisição e manutenção de um único bloqueio de tabela geralmente requer menos sobrecarga do que vários bloqueios de linha individuais.

Este tutorial se destinou a apresentar a você o conceito de consistência de dados e os mecanismos que o DB2 usa para manter a consistência de dados em ambientes de banco de dados de usuário único e multiusuário. Também ajudará você a se preparar para o exame de certificação DB2 10.1 Fundamentals (Exame 610). Agora você deve entender melhor a simultaneidade de dados e ser capaz de:

  • Identificar fatores que influenciam bloqueio
  • Listar objetos nos quais bloqueios podem ser obtidos
  • Utilizar a instrução LOCK TABLE adequadamente
  • Identificar características de bloqueios do DB2
  • Identificar os níveis de isolamento que devem ser usados em uma determinada situação
  • Saber como e quando usar a semântica atualmente confirmada (CC)

Recursos

Aprender

Obter produtos e tecnologias

  • Crie seu próximo projeto de desenvolvimento com o software de avaliação da IBM, disponível para download diretamente no developerWorks.
  • Agora é possível usar o DB2 gratuitamente. Faça o download do O DB2 Express-C, uma versão gratuita do DB2 Express Edition para a comunidade que oferece os mesmos recursos de dados centrais que o DB2 Express Edition e fornece uma base sólida para desenvolver e implementar aplicativos.

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Information Management
ArticleID=836422
ArticleTitle=Preparação para o Exame de Certificação DB2 10.1 Fundamentals (Exame 610), Parte 6: Simultaneidade de Dados
publish-date=09252012