Escolar Documentos
Profissional Documentos
Cultura Documentos
O objetivo deste artigo descrever o comportamento do sistema gerenciador de banco de dados PostgreSQL, quando duas ou mais sesses tentam acessar os mesmos dados ao mesmo tempo. O objetivo nesta situao permitir o acesso eficiente para todas as sesses mantendo, ao mesmo tempo, uma rigorosa integridade dos dados. Todos os desenvolvedores de aplicao de banco de dados devem estar familiarizados com os tpicos cobertos por este captulo.
1. Introduo
Diferentemente dos sistemas gerenciadores de banco de dados tradicionais, que usam bloqueios para realizar o controle de concorrncia, o PostgreSQL mantm a consistncia dos dados utilizando o modelo multiverso (Multiversion Concurrency Control, MVCC). Isto significa que ao consultar o banco de dados, cada transao enxerga um instantneo (snapshot) dos dados (uma verso do banco de dados) conforme estes dados eram h algum tempo atrs, sem levar em considerao o estado corrente dos dados subjacentes. Este modelo impede que a transao enxergue dados inconsistentes, que poderiam ser causados por atualizaes feitas por transaes concorrentes nas mesmas linhas de dados, fornecendo um isolamento da transao para cada uma das sesses do banco de dados. A diferena principal entre os modelos multiverso e de bloqueio que, no MVCC, os bloqueios obtidos para consultar (ler) os dados no conflitam com os bloqueios obtidos para escrever os dados e, portanto, a leitura nunca bloqueia a escrita, e a escrita nunca bloqueia a leitura. As funcionalidades de bloqueio, no nvel de tabela e de linha, tambm esto disponveis no PostgreSQL para aplicaes que no podem se adaptar facilmente ao comportamento MVCC. Entretanto, a utilizao apropriada do MVCC geralmente produz um desempenho melhor que os bloqueios.
2. Isolamento da transao
O padro SQL define quatro nveis de isolamento de transao em termos de trs fenmenos que devem ser evitados entre transaes concorrentes. Os fenmenos no desejveis so: dirty read (leitura suja) A transao l dados no efetivados (uncommitted) escritos por uma transao concorrente. nonrepeatable read (leitura que no pode ser repetida) A transao l uma segunda vez os dados, e descobre que os dados foram modificados por outra transao (que os efetivou aps ter sido feita a leitura anterior). phantom read (leitura fantasma) A transao executa uma segunda vez uma consulta que retorna um conjunto de linhas que satisfaz uma determinada condio de procura, e descobre que o conjunto de linhas que satisfaz a condio diferente devido a uma outra transao efetivada recentemente.
Os quatro nveis de isolamento de transao, e seus comportamentos correspondentes, esto descritos na Tabela 9-1. Tabela 9-1. Nveis de isolamento da transao no SQL Nvel de isolamento Read uncommitted Read committed Repeatable read Serializable Dirty Read Possvel Impossvel Impossvel Impossvel Nonrepeatable Read Possvel Possvel Impossvel Impossvel Phantom Read Possvel Possvel Possvel Impossvel
Se duas transaes deste tipo tentam mudar concorrentemente o saldo da conta 12345 claro que se deseja que a segunda transao comece a partir da verso atualizada da linha da conta. Como cada comando afeta apenas uma linha predeterminada, permitir enxergar a verso atualizada da linha no cria nenhuma inconsistncia problemtica. Uma vez que no modo Read Committed cada novo comando comea com um novo instantneo, incluindo todas as transaes efetivadas at este instante, os comandos seguintes na mesma transao sempre enxergam os efeitos das transaes concorrentes efetivadas. O ponto em questo se dentro de um nico comando enxergada uma viso totalmente consistente do banco de dados. O isolamento parcial da transao fornecido pelo modo Read Committed adequado para muitas aplicaes, e este modo rpido e fcil de ser utilizado. Entretanto, para aplicaes que efetuam consultas e atualizaes complexas, pode ser necessrio garantir uma viso consistente mais rigorosa do banco de dados que a fornecida pelo modo Read Committed.
porque uma transao serializvel no pode modificar linhas alteradas por outra transao aps ter comeado. Quando uma aplicao recebe esta mensagem de erro, deve abortar a transao corrente e tentar executar novamente toda a transao a partir do incio. Da segunda vez em diante, a transao passa a enxergar a modificao efetivada anteriormente como parte da sua viso inicial do banco de dados e, portanto, no existir conflito lgico em usar a nova verso da linha como o ponto de partida para a atualizao na nova transao.
Observe que somente as transaes que atualizam podem precisar de novas tentativas --- as transaes apenas de leitura nunca ocasionam conflito de serializao. O modo serializvel fornece uma garantia rigorosa que cada transao enxerga apenas vises completamente consistentes do banco de dados. Entretanto, a aplicao precisa estar preparada para executar novamente as transaes quando as atualizaes concorrentes tornam impossvel sustentar a iluso de uma execuo serial. Uma vez que o custo de refazer transaes complexas pode ser significativo, este modo recomendado somente quando as transaes efetuando atualizaes contm lgica suficientemente complexa a ponto de produzir respostas erradas no modo Read Committed. Habitualmente, o modo serializvel necessrio quando a transao realiza vrias consultas sucessivas que necessitam enxergar vises idnticas do banco de dados.
3. Bloqueio explcito
O PostgreSQL fornece vrios modos de bloqueio para controlar o aceso concorrente aos dados nas tabelas. Estes modos podem ser utilizados para o bloqueio controlado pela transao, nas situaes onde o MVCC no fornece o comportamento adequado. Tambm, a maioria dos comandos do PostgreSQL obtm, automaticamente, bloqueios com modos apropriados para garantir que as tabelas referenciadas no sero excludas ou modificadas de forma incompatvel enquanto o comando executa (Por exemplo, o comando ALTER TABLE no pode executar concorrentemente com outras operaes na mesma tabela).
Modos de bloqueio no nvel de tabela: ACCESS SHARE Conflita apenas com o modo de bloqueio ACCESS EXCLUSIVE. O comando SELECT obtm um bloqueio deste modo nas tabelas referenciadas. Em geral, qualquer comando que apenas l a tabela sem modific-la obtm este modo de bloqueio. ROW SHARE Conflita com os modos de bloqueio EXCLUSIVE e ACCESS EXCLUSIVE. O comando SELECT FOR UPDATE obtm o bloqueio neste modo na(s) tabela(s) de destino (alm do bloqueio no modo ACCESS SHARE para as demais tabelas referenciadas mas no selecionadas FOR UPDATE). ROW EXCLUSIVE Conflita com os modos de bloqueio SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE e ACCESS EXCLUSIVE. os comandos UPDATE, DELETE e INSERT obtm este modo de bloqueio na tabela de destino (alm do modo de bloqueio ACCESS SHARE nas outras tabelas referenciadas). Em geral, este modo de bloqueio obtido por todos os comandos que modificam os dados da tabela. SHARE UPDATE EXCLUSIVE Conflita com os modos de bloqueio SHARE UPDATE EXCLUSIVE, SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE e ACCESS EXCLUSIVE. Este modo protege a tabela contra mudanas concorrentes no esquema e a execuo do comando VACUUM. Obtida pelo comando VACUUM (sem a opo FULL). SHARE Conflita com os modos de bloqueio ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE ROW EXCLUSIVE, EXCLUSIVE e ACCESS EXCLUSIVE. Este modo protege a tabela contra mudanas concorrentes nos dados. Obtido pelo comando CREATE INDEX. SHARE ROW EXCLUSIVE Conflita com os modos de bloqueio ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE e ACCESS EXCLUSIVE. Este modo de bloqueio no obtido automaticamente por nenhum comando do PostgreSQL. EXCLUSIVE Conflita com os modos de bloqueio ROW SHARE, ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE e ACCESS EXCLUSIVE. Este modo permite apenas ACCESS SHARE concorrente, ou seja, somente leituras da tabela podem prosseguir em paralelo com uma transao que obteve este modo de bloqueio. Este modo de bloqueio no obtido automaticamente por nenhum comando do PostgreSQL.
ACCESS EXCLUSIVE Conflita com todos os modos de bloqueio (ACCESS SHARE, ROW SHARE, ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE e ACCESS EXCLUSIVE). Este modo garante que a transao que o obteve a nica acessando a tabela de qualquer forma. Obtido pelos comandos ALTER TABLE, DROP TABLE e VACUUM FULL. Este , tambm, o modo de bloqueio padro para o comando LOCK TABLE sem a especificao explcita do modo. Nota: Somente o bloqueio ACCESS EXCLUSIVE bloqueia o comando SELECT (sem a clusula FOR UPDATE).
3.3. Impasses
A utilizao de bloqueios explcitos pode causar impasses (deadlocks), em particular quando duas (ou mais) transaes mantm bloqueios que outra deseja. Por exemplo, se a transao 1 obtm um bloqueio exclusivo na tabela A e, ento, tenta obter um bloqueio exclusivo na tabela B, enquanto a transao 2 j possui um bloqueio exclusivo na tabela B, e agora tenta obter um bloqueio exclusivo na tabela A, ento nenhuma das duas transaes pode continuar. O PostgreSQL detecta automaticamente as situaes de impasse, resolvendo-as abortando uma das transaes envolvidas, permitindo que a(s) outra(s) prossiga(m) (Exatamente qual transao abortada difcil prever, no se devendo confiar nesta previso). Geralmente, a melhor defesa contra os impasses evit-los tendo certeza que todas as aplicaes que utilizam o banco de dados obtm estes bloqueios em vrios objetos em uma ordem consistente. Deve ser garantido, tambm, que o primeiro bloqueio de um objeto em uma transao seja aquele com o modo mais elevado que ser necessrio para este objeto. Se no for possvel conhecer esta situao antecipadamente, ento os impasses podem ser tratados em tempo de execuo tentando novamente a execuo das transaes abortadas pelos impasses.
Enquanto a situao de impasse no detectada, uma transao aguardando um bloqueio no nvel de tabela ou no nvel de linha fica aguardando indefinidamente pela liberao do bloqueio conflitante. Por isso, uma pssima idia as aplicaes manterem transaes abertas por longos perodos (por exemplo, aguardando a entrada de dados pelo usurio).
Observe tambm que, quando a preveno contra alteraes concorrentes est baseada em bloqueios explcitos, deve ser utilizado o modo Read Committed, ou tomar-se o cuidado de obter os bloqueios antes de executar os comandos no modo serializvel. Um bloqueio explcito obtido em uma transao serializvel garante que nenhuma outra transao modificando a tabela est executando --mas se o instantneo enxergado pela transao for anterior obteno do bloqueio, pode ser que seja anterior a algumas mudanas na tabela que agora esto efetivadas. Um instantneo de uma transao serializvel , na verdade, tirado no incio do primeiro comando (SELECT, INSERT, UPDATE ou DELETE) sendo, portanto, possvel obter o bloqueio explcito antes do instantneo ser tirado.
5. Bloqueio e ndices
Embora o PostgreSQL fornea acesso de leitura e gravao no bloqueante aos dados das tabelas, o acesso de leitura e gravao no bloqueante no oferecido, atualmente, para todos os mtodos de acessos dos ndices implementados pelo PostgreSQL. Os tipos de ndices existentes so implementados do seguinte modo: ndices B-tree So utilizados bloqueios compartilhados/exclusivos no nvel de pgina, de curta durao, para acesso de leitura/gravao. Os bloqueios so liberados imediatamente aps cada tupla do ndice ser lida ou inserida. Os ndices B-tree fornecem a concorrncia mais elevada sem condies de impasse. ndices GiST e R-tree So utilizados bloqueios compartilhados/exclusivos no nvel de ndice para acessos de leitura/gravao. Os bloqueios so liberados aps a declarao (comando) ser executada. ndices Hash So utilizados bloqueios compartilhados/exclusivos no nvel de pgina para acessos de leitura/gravao. Os bloqueios so liberados aps a pgina ser processada. Os bloqueios no nvel de pgina permitem uma concorrncia melhor que o bloqueio no nvel de ndice, mas podem ocasionar impasses. Em resumo, o ndice B-tree o tipo de ndice recomendado para as aplicaes correntes.