CONTROLE DE CONCORRÊNCIA EM BANCO DE DADOS: Estudo de Caso – Microsoft SQL Server 2008 GERALDA SILVIA DE VASCONCELOS JARDIM 1 IREMAR NUNES DE LIMA 2 Resumo: Este artigo descreve a importância do mecanismo de controle de concorrência de transações nos SGBDs relacionais, enfatizando as técnicas de controle de concorrência implementadas pelo Microsoft SQL Server 2008 Palavras-chave: Banco de Dados,Transação,Controle de Concorrência, Microsoft SQL Server 2005. 1 2 Pós Graduada em Banco de Dados e Business Intelligence ([email protected]). Mestre em informática e professor do centro universitário Newton Paiva ([email protected]). 2 1. INTRODUÇÃO A disseminação global da tecnologia possibilitou a todas as pessoas, em qualquer parte do mundo, o uso de informações geradas pelos sistemas computacionais multiprocessados, com isto o paralelismo é inevitável. Em um Sistema Gerenciador de Banco de Dados (SGBD) multiusuário, os dados são acessados simultaneamente por usuários ou por programas de aplicação, recuperando e modificando o banco de dados, muitas vezes alterando a mesma informação, tornando as transações concorrentes. Desta forma torna-se relevante discutir qual o papel dos SGBDs no controle desta concorrência num banco de dados. Segundo ELMASRI (2005, p.400), a concorrência de transações não controlada pode levar o banco de dados a um estado inconsistente, com diversas anomalias. Visando demonstrar a real necessidade do controle de concorrência e como ele é feito, este artigo utiliza como estudo de caso o SGBD Microsoft SQL Server 2008. O artigo tem como objetivo geral demonstrar o mecanismo de controle de concorrência nos SGBDs relacionais, enfatizando as técnicas de controle de concorrência implementadas pelo Microsoft SQL Server 2008. Como objetivos específicos o artigo aborda os conceitos relacionados a controle de concorrência de transações dos Sistemas Gerenciadores de Banco de Dados, discute porque o controle de concorrência é necessário em sistemas multiusuários, aponta as propriedades e técnicas básicas no processamento de transações acerca de controle de concorrência e restauração e demonstra como os conceitos de transação são implementados no Microsoft SQL Server 2008. O restante deste trabalho está organizado da seguinte forma: a seção 2 aborda como a execução concorrente de transações se comporta em sistemas multiusuários; a seção 3 trata 3 de como o controle de concorrência acontece no Microsoft SQL Server 2008; na seção 4 será apresentada a conclusão deste trabalho. 2. PROCESSAMENTO DE TRANSAÇÕES O controle de concorrência em um SGBD está relacionado diretamente com os comandos de acesso a banco de dados feitos por uma transação. Segundo Battisti (2005, p.244), transação é um conjunto de operações sobre os dados, que deve acontecer como um todo. Todas as operações devem ser finalizadas com sucesso, ou nenhuma delas deve ser realizada. Caso uma das operações, contida na transação, venha a falhar, as operações ainda pendentes devem ser canceladas e as operações já realizadas devem ser revertidas. Desta forma uma transação sempre estará completa ou não foi realizada. Transações submetidas por vários usuários podem ser executadas concorrentemente e diversos problemas podem ocorrer no banco de dados se esta concorrência não for devidamente controlada. De acordo com ELMASRI (2005, p.400), dentre os principais problemas, podem ser destacados os seguintes: • Atualização perdida: ocorre quando duas transações que acessam os mesmos itens de bancos de dados tiveram suas operações intercaladas. • Atualização temporária (Leitura Suja): ocorre quando uma transação atualizar um item de banco de dados e, a seguir, falhar por alguma razão. Este item pode ser acessado por uma outra transação antes que ele retorne ao seu valor original. • Sumário Incorreto: se uma transação aplicar uma função agregada para sumário de um número de registros enquanto outras transações estiverem atualizando alguns desses 4 registros, pode acontecer da função agregada calcular alguns valores antes de eles serem atualizados e outros depois de feita a atualização. Para efeito de restauração, o sistema precisa manter o controle de quando a transação inicia, termina e de suas efetivações ou interrupções. De acordo com (ELMASRI, 2005, p.403), durante sua execução, uma transação, percorre os seguintes estados: • Estado Ativo: imediatamente após o início de sua execução. • Estado de efetivação parcial: quando a transação termina, mas ainda precisa garantir que nenhuma falha impossibilite a gravação permanente das mudanças. • Estado de efetivação: as gravações serão gravadas permanentemente no banco de dados (commit) A figura 1 abaixo ilustra os estados de uma transação. Figura 1 – Diagrama de transição de estados de execução de uma transação. Fonte: Sistemas de Bancos de Dados. 4ª ed. São Paulo: Person Addison Wesley, 2005, 724 p. O controle de concorrência e métodos de restauração do SGBD deverão impor algumas propriedades às transações que são chamadas propriedades ACID (ELMASRI, 2005, p.404), descritas a seguir: 9 Atomicidade: uma transação é uma unidade atômica de processamento; ou ela será executada em sua totalidade ou não será de modo nenhum. 9 Consistência: uma transação será preservadora de consistência se sua execução 5 completa fizer o banco de dados passar de um estado consistente para outro. 9 Isolamento: uma transação dever ser executada como se estivesse isolada das demais. Isto é, a execução de uma transação não deve sofrer interferência de quaisquer outras transações concorrentes. 9 Durabilidade: as mudanças aplicadas ao banco de dados por uma transação efetivada devem persistir no banco de dados. Essas mudanças não devem ser perdidas em razão de uma falha. Conforme ressaltado por ELMASRI (2005, p.415), para assegurar a propriedade de não interferência ou isolamento de transações concorrentes, os SGBDs utilizam protocolos. O protocolo de controle de concorrência mais usado é o bloqueio. O usuário pode indicar o grau de isolamento desejado entre transações, definindo como será feito o bloqueio dos dados. O nível de isolamento é especificado pela declaração ISOLATION LEVEL <isolamento>, onde o valor de <isolamento> pode ser READ UNCOMMITTED (leitura não eftivada), READ COMMITTED (leitura efetivada), REPEATABLE READ (leitura repetível) ou SERIALIZABLE (serializável). O nível de isolamento padrão é SERIALIZABLE, entretanto, alguns sistemas usam como padrão o READ COMMITTED. O nível SERIALIZABLE não permite violações que causam leitura de sujeira, leitura não repetível e fantasmas. Se uma transação for executada em um nível de isolamento mais baixo que o SERIALIZABLE, podem ocorrer as seguintes violações: 9 Leitura suja ( dirty read ): uma transação T1 pode ler a atualização de uma transação T2, que ainda não tenha sido committed. Se T2 falhar e for abortada, então T1 terá lido um valor que não existe e é incorreto. 6 9 Leitura não repetitiva ( nonrepeatable read ): uma transação T1 pode ler um dado valor de uma tabela. Se outra transação T2 posteriormente atualizar este valor e T1 ler novamente esse valor, T1 verá um novo valor. 9 Fantasmas ( phantoms ): uma transação T1 pode ler um conjunto de linhas de uma tabela, com base, talvez, em alguma condição especificada na cláusula WHERE da SQL. Suponha que uma transação T2 insira uma nova linha que também satisfação à condição da cláusula WHERE empregada em T1, na tabela utilizada por T1. Se T1 for repetida, então T1 verá um fantasma, uma linha que antes não existia. Segue abaixo a figura 2 apresentando as possíveis violações baseadas em níveis de isolamento. Nível de isolamento Leitura não efetivada Leitura efetivada Leitura Repetitiva Serializável Leitura Suja Sim Não Não Não Não-Repetível Sim Sim Não Não Fantasmas Sim Sim Sim Não Figura 2 – Possíveis violações baseadas em Níveis de Isolamento Fonte: Sistemas de Bancos de Dados. 4ª ed. São Paulo: Person Addison Wesley, 2005, 724 p. 3. CONTROLE DE CONCORRÊNCIA NO SQL SERVER 2008 O SGBD Microsoft SQL Server 2008 usa dois mecanismos para garantir a integridade de transações e manter a consistência dos bancos de dados quando vários usuários estão acessando os dados ao mesmo tempo (Microsoft SQL Server 2008 Books Online - July 2009). O primeiro mecanismo é o bloqueio: um mecanismo usado para sincronizar o acesso de vários usuários à mesma parte dos dados simultaneamente. Antes que uma transação 7 adquira uma dependência de uma parte dos dados no estado atual, como ler ou modificar os dados, ela deve se proteger contra os efeitos de outra transação que modifique os mesmos dados. A transação faz isso, solicitando um bloqueio na parte dos dados. O modo de bloqueio define o nível de dependência que a transação tem nos dados. Nenhuma transação pode receber um bloqueio que conflite com o modo de um bloqueio já atribuído àqueles dados por outra transação. Se uma transação requisitar um modo de bloqueio que conflite com um bloqueio que já tenha sido atribuído aos mesmos dados, a instância do mecanismo de banco de dados fará uma pausa na transação requerida até que o primeiro bloqueio seja liberado. Quando uma transação modifica uma parte dos dados, ela mantém o bloqueio protegendo a modificação até o fim da transação. O tempo que uma transação mantém os bloqueios adquiridos, para proteger as operações de leitura, depende da configuração do nível de isolamento da transação. Todos os bloqueios mantidos por uma transação são liberados quando a transação for concluída. Os bloqueios são administrados internamente pelo gerenciador de bloqueio do SQL Server. Ao processar uma instrução Transact-SQL, o processador de consulta determina quais recursos devem ser acessados. O processador de consulta determina que tipos de bloqueio são necessários para proteger cada recurso baseado no tipo de acesso e no nível configurado de isolamento da transação. O processador de consulta solicita os bloqueios apropriados ao gerenciador de bloqueio. O gerenciador de bloqueio concede os bloqueios caso não haja bloqueios conflitantes mantidos por outras transações (Microsoft SQL Server 2008 Books Online - July 2009). O SQL Server 2008 tem bloqueio multigranular que permite uma transação bloquear diferentes tipos de recursos. Para minimizar o custo de bloqueio, ele bloqueia recursos automaticamente, em um nível apropriado para a tarefa. Bloquear em uma granularidade 8 menor como, por exemplo, linhas, aumenta a concorrência, mas tem uma sobrecarga maior de memória, devido à exigência de mais bloqueios mantidos, se muitas linhas forem bloqueadas. Bloqueando em uma granularidade maior, como tabelas, diminui a concorrência, porque bloquear a tabela inteira restringe o acesso a qualquer parte da tabela por outras transações. No entanto, tem uma sobrecarga menor de memória, porque menos bloqueios serão mantidos. A tabela 1 seguinte mostra os recursos que podem ser bloqueados pelo SQL Server 2008. Recurso Descrição RID Um identificador de linha usado para bloquear uma única linha dentro de um heap. KEY Um bloqueio de linha dentro de um índice usado para proteger um intervalo de chaves em transações serializáveis. PAGE Uma página de 8 quilobytes (KB) em um banco de dados, como dados ou páginas de índice. EXTENT Um grupo contíguo de oito páginas, como dados ou páginas de índice. HoBT Um heap ou árvore B. Um bloqueio protegendo uma árvore B (índice) ou o heap de páginas de dados que não tem um índice clusterizado. TABLE A tabela inteira, inclusive todos os dados e índices. FILE Um arquivo de banco de dados. APPLICATION Um recurso de aplicativo especificado. METADATA Bloqueios de metadados. ALLOCATION_UNIT Uma unidade de alocação. 9 DATABASE O banco de dados inteiro. Tabela 1 – Modos de Bloqueios utilizados pelo SQL Server 2008 Fonte: Microsoft SQL Server 2008 Books Online, Bloqueio de Granularidade e Hierarquia A tabela 2 a seguir, mostra os modos de bloqueio que o SQL Server 2008 utiliza. Modos de bloqueio Descrição Compartilhado Usado para operações de leitura que não alteram ou atualizam dados, como uma (S) instrução SELECT. Atualização (U) Usado em recursos que podem ser atualizados. Evita uma forma comum de deadlock que ocorre quando várias sessões estão lendo, bloqueando e atualizando recursos. Exclusivo (X) Usado para operações da modificação de dados, como INSERT, UPDATE ou DELETE. Assegura que várias atualizações não sejam realizadas no mesmo recurso e ao mesmo tempo. Intencional Usado para estabelecer uma hierarquia de bloqueio. Os tipos de bloqueios intencionais são: tentativa compartilhada (IS), exclusivo de tentativa (IX) e compartilhado com exclusivo de tentativa (SIX). Esquema Usado quando uma operação dependente do esquema de uma tabela está executando. Os tipos de bloqueios de esquema são: modificação de esquema (SchM) e estabilidade de esquema (Sch-S). Atualização em Usado quando para copiar dados em massa em uma tabela e o hint TABLOCK foi massa (BU). especificado. Intervalo de chave Protege o intervalo de leitura de linhas lido por uma consulta ao usar o nível de 10 isolamento da transação serializável. Assegura que outras transações não possam inserir linhas que se qualifiquem para consultas da transação serializável se as consultas forem executadas novamente. Tabela 2 – Modos de Bloqueios utilizados pelo SQL Server 2008 Fonte: Microsoft SQL Server 2008 Books Online, Modos de Bloqueio A tabela 3 a seguir mostra a compatibilidade dos modos de bloqueio mais comumente encontrados. Modo concedido existente Modo solicitado IS S U IX SIX X Tentativa compartilhada (IS) Sim Sim Sim Sim Sim Não Compartilhado (S) Sim Sim Sim Não Não Não Atualização (U) Sim Sim Não Não Não Não Exclusivo da tentativa (IX) Sim Não Não Sim Não Não Compartilhado com exclusivo da tentativa (SIX) Sim Não Não Não Não Não Exclusivo (X) Não Não Não Não Não Não Tabela 3 – Compatibilidade dos modos de bloqueio no SQL Server 2008 Fonte: Microsoft SQL Server 2008 Books Online, Compatibilidade de Bloqueios O segundo mecanismo é o Controle de Versão de Linha. Ao habilitar um nível de isolamento baseado em controle de versão de linha, o SQL Server mantém versões de cada linha modificada. Os aplicativos podem especificar que uma transação use as versões da linha para exibir dados da forma como eram no início da transação ou consulta ao invés de 11 proteger todas as leituras com bloqueios. Usando o controle de versão de linha, a possibilidade de uma operação de leitura bloquear outras transações é muito reduzida. Os usuários podem controlar a implementação do controle de versão de linha habilitando ou desabilitando as opções do banco de dados. O SQL Server apresenta dois tipos de níveis de isolamento de transação ao se usar o controle de versão de linha, descritos a seguir: • Confirmado por leitura: É gerado um instantâneo no nível da instrução. • Instantâneo: É gerado um instantâneo no nível da transação. O isolamento confirmado por leitura que usa controle de versão de linha é habilitado pela configuração da opção de banco de dados READ_COMMITTED_SNAPSHOT como ON. O isolamento do instantâneo é habilitado pela configuração da opção de banco de dados ALLOW_SNAPSHOT_ISOLATION como ON. Sempre que uma transação modifica uma linha, uma imagem da linha antes da modificação é copiada em uma página no armazenamento de versão. O armazenamento de versão é uma coleção de páginas de dados localizada no BD tempdb. Se várias transações modificarem uma linha, várias versões da linha serão vinculadas em uma cadeia de versão. As operações de leitura que usam o controle de versão de linha recuperam a última versão de cada linha confirmada quando a transação ou instrução foi iniciada. Para transações que usam um nível de isolamento baseado no controle de versão de linha, as operações de leitura não solicitam bloqueios compartilhados nos dados. Isso significa que os leitores que usam controle de versão de linha não bloqueiam outros leitores ou gravadores que estiverem acessando os mesmos dados. Da mesma maneira, os gravadores não bloqueiam os leitores. Porém, os gravadores bloquearão uns aos outros até mesmo durante a execução em níveis de isolamento com base em controle de versão de linha, pois mais de uma operação de gravação não podem 12 modificar os mesmos dados ao mesmo tempo (Microsoft SQL Server 2008 Books Online July 2009). Ao alterar a opção de banco de dados READ_COMMITTED_SNAPSHOT ou ALLOW_SNAPSHOT_ISOLATION para ON, o SQL Server atribuirá um número de seqüência da transação (XSN) para cada transação que manipular dados usando o controle de versão. As transações iniciam quando uma instrução BEGIN TRANSACTION é executada. Porém, o número de seqüência da transação inicia com a primeira operação de leitura ou gravação depois da instrução BEGIN TRANSACTION. O número de seqüência da transação é incrementado um por vez sempre que é atribuído (Microsoft SQL Server 2008 Books Online - July 2009). Cada versão é marcada com o número de seqüência da transação que fez a alteração. As versões das linhas modificadas são encadeadas usando uma lista de links. O valor da linha mais recente sempre é armazenado no banco de dados atual e encadeado às linhas com controle de versão armazenadas no tempdb. As versões da linha são mantidas por tempo suficiente para atender os requisitos das transações executadas em níveis de isolamento com base em controle de versão de linha. O SQL Server localiza o número útil mais antigo de seqüência da transação e exclui periodicamente todas as versões da linha carimbadas com números de seqüência da transação inferiores ao número útil mais antigo da seqüência (Microsoft SQL Server 2008 Books Online - July 2009). Ao iniciar uma transação que usa o nível de isolamento do instantâneo, o SQL Server registra todas as transações atualmente ativas. Quando a transação de instantâneo lê uma linha que tem uma cadeia de versão, o SQL Server segue a cadeia e recupera a linha em que o número de seqüência da transação está mais próxima, mas inferior ao número de seqüência da transação de instantâneo que está lendo a linha e não está na lista das 13 transações ativas quando a transação de instantâneo é iniciada (Microsoft SQL Server 2008 Books Online - July 2009). As operações de leitura executadas por uma transação de instantâneo recuperam a última versão de cada linha confirmada quando a transação de instantâneo foi iniciada. Isso fornece um instantâneo transacional consistente dos dados, da mesma forma como existiam no início da transação (Microsoft SQL Server 2008 Books Online - July 2009). As transações de leitura confirmada que usam controle de versão de linha funcionam de forma semelhante. A diferença é que a transação de leitura confirmada não usa o seu próprio número de seqüência da transação ao escolher versões de linha. Cada vez que uma instrução é iniciada, a transação de leitura confirmada lê o último número de seqüência da transação emitido para aquela instância. Esse é o número de seqüência da transação usado para selecionar as versões de linha corretas para aquela instrução. Isso permite que as transações de leitura confirmada veja um instantâneo dos dados como ele era no início de cada instrução (Microsoft SQL Server 2008 Books Online - July 2009). Em uma transação de leitura confirmada que usa o controle de versão de linha, a seleção de linhas a serem atualizadas é feita usando uma verificação de bloqueio em que um bloqueio de atualização (U) é feito na linha de dados conforme os valores dos dados são lidos. Isso é igual à transação confirmada por leitura que não usa controle de versão de linha. Se a linha de dados não atender os critérios de atualização, o bloqueio de atualização será liberado naquela linha e a próxima linha será fechada e verificada (Microsoft SQL Server 2008 Books Online - July 2009). As transações executadas em isolamento de instantâneo usam uma abordagem otimista para modificação de dados adquirindo bloqueios em dados antes de executar a modificação somente para impor restrições. Do contrário, os bloqueios não são adquiridos em dados até 14 que os dados sejam modificados. Quando uma linha de dados atende os critérios de atualização, a transação de instantâneo verifica se a linha de dados não foi modificada por uma transação simultânea que foi confirmada depois do início da transação de instantâneo. Se a linha de dados tiver sido modificada fora da transação de instantâneo, ocorrerá um conflito de atualização e a transação de instantâneo será finalizada. O conflito de atualização é controlado pelo SQL Server e não há como desabilitar a detecção de conflito de atualização (Microsoft SQL Server 2008 Books Online - July 2009). A tabela 4 a seguir, resume as diferenças entre o isolamento de instantâneo e o isolamento de leitura confirmada usando o controle de versão de linha. Nível de isolamento de leitura confirmada usando o controle de versão Propriedade de linha Nível de isolamento do instantâneo A opção de READ_COMMITTED_SNAPSHOT ALLOW_SNAPSHOT_ISOLATION Como uma Use o nível padrão de isolamento de Exige a execução de SET sessão solicita leitura confirmada ou execute a instrução TRANSACTION ISOLATION LEVEL o tipo SET TRANSACTION ISOLATION para especificar o nível de isolamento específico de LEVEL para especificar o nível de SNAPSHOT antes do início da transação. banco de dados que deve ser definida como ON para habilitar o suporte exigido. 15 controle de isolamento READ COMMITTED. Isso versão de pode ser feito depois do início da linha. transação. A versão dos Todos os dados que foram confirmados Todos os dados que foram confirmados dados lidos antes do início de cada instrução. antes do início de cada transação. Como as Faz a reversão de versões de linha a dados Usa versões de linha para selecionar atualizações reais para selecionar as linhas que devem linhas a serem atualizadas. Tenta adquirir são ser atualizadas e usa os bloqueios de um bloqueio exclusivo na linha de dados controladas. atualização nas linhas de dados reais a ser modificada e, se os dados selecionadas. Adquire bloqueios tiverem sido modificados por outra exclusivos em linhas de dados atuais a transação, ocorrerá um conflito de serem modificadas. Nenhuma detecção de atualização e a transação de instantâneo conflito de atualização. será finalizada. Nenhum. Suporte integrado. Não pode ser por instruções. Atualização de detecção desabilitado. de conflito. Tabela 4 – Diferenças entre o isolamento de instantâneo e o isolamento de leitura confirmada Fonte: Microsoft SQL Server 2008 Books Online 4. CONCLUSÃO. Transações concorrentes necessitam ser controladas pelos SGBDs de forma que a execução de uma transação não pode ser afetada por outra. O mecanismo de controle de concorrência de um SGBD, deve garantir que todas as operações de uma transação sejam completadas com sucesso para ter seu efeito gravado permanentemente no Bando de 16 Dados, caso contrário, se uma das operações da transação falhar, todas as operações já executadas deverão ser canceladas. O SGBD Microsoft SQL Server 2008 apresenta dois mecanismos para garantir a integridade de transações e manter a consistência dos bancos de dados: o bloqueio e o controle de versão de linhas. Antes de decidir usar o isolamento com base em controle de versão de linha é necessário verificar o benefício de simultaneidade de minimizar o bloqueio contra o custo do aumento de recurso necessário para manter e ler estas versões. REFERÊNCIAS BATTISTI, Julio. SQL Server 2005: administração & desenvolvimento: curso completo. Rio de Janeiro: Axcel Books, 2005, 990 p. ELMASRI, Rames; NAVATHE, Shamkant B.Sistemas de Banco de dados. 4ª ed. São Paulo: Person Addison Wesley, 2005, 724 p. Microsoft SQL Server 2008 Books Online - July 2009