Entender o bloqueio
O MVCC (Controle de Simultaneidade de Várias Versões) fornece as configurações de simultaneidade apropriadas para a maioria dos cenários. No entanto, se um aplicativo exige bloqueios específicos que controlam exatamente quais linhas são afetadas e com um nível de bloqueio específico, os modos de bloqueio explícito permitem esse controle refinado.
No Banco de Dados do Azure para PostgreSQL, há três tipos de bloqueio explícito: bloqueios no nível de tabela, bloqueios no nível de linha e bloqueios no nível de página. A transação inicial solicita um bloqueio e, se ela é aceita, o bloqueio solicitado passa a ser o bloqueio existente. Se outra transação tentar bloquear os mesmos dados, o bloqueio será concedido se ele não entrar em conflito com a transação original.
Por exemplo, duas transações podem consultar os mesmos dados simultaneamente com uma instrução SELECT. Essas solicitações usarão um bloqueio ACCESS SHARE e ambas as transações serão permitidas. Em outro cenário, uma transação está consultando dados com uma instrução SELECT e um bloqueio ACCESS SHARE, mas ao mesmo tempo, outra transação tenta remover a mesma tabela. A remoção de uma tabela exige um bloqueio ACCESS EXCLUSIVE, o que não será concedido neste cenário.
Bloqueio no nível de tabela
Os bloqueios no nível de tabela adquirem bloqueios em uma tabela inteira, mesmo o nome deles contenha ROW. Bloquear uma tabela inteira pode ser necessário se a tabela em si está sendo modificada, ou pode ser mais eficiente do que remover muitos bloqueios no nível de linha.
Há oito tipos de bloqueio de nível de tabela no Banco de Dados do Azure para PostgreSQL e os comandos SQL que adquirem esses tipos de bloqueio são:
Modo de Bloqueio | Adquirido por |
---|---|
ACCESS SHARE | Comando SELECT |
ROW SHARE | Comandos SELECT FOR UPDATE e SELECT FOR SHARE |
ROW EXCLUSIVE | Comandos UPDATE, DELETE e INSERT |
SHARE UPDATE EXCLUSIVE | Comandos ANALYZE, CREATE INDEX CONCURRENTLY, CREATE STATISTICS, COMMENT ON, REINDEX CONCURRENTLY, alguns comandos ALTER INDEX e ALTER TABLE e VACUUM (não FULL) |
COMPARTILHAR | Comando CREATE INDEX (não CONCURRENTLY) |
SHARE ROW EXCLUSIVE | Comando CREATE TRIGGER e alguns comandos ALTER TABLE |
EXCLUSIVE | Comando REFRESH MATERIALIZED VIEW CONCURRENTLY |
ACCESS EXCLUSIVE | Comandos DROP TABLE, REINDEX, TRUNCATE, CLUSTER, REFRESH MATERIALIZED VIEW (não CONCURRENTLY), a maioria dos comandos ALTER INDEX e ALTER TABLE e VACUUM FULL |
Cada tipo de bloqueio existente bloqueia outros bloqueios solicitados que estão sendo adquiridos. A seguinte tabela lista os bloqueios que impedem outros bloqueios de serem adquiridos:
-- | ACCESS SHARE existente | ROW SHARE existente | ROW EXCLUSIVE existente | SHARE UPDATE EXCLUSIVE existente | SHARE existente | SHARE ROW EXCL existente | EXCLUSIVE existente | ACCESS EXCLUSIVE existente |
---|---|---|---|---|---|---|---|---|
ACCESS SHARE solicitado | Bloqueado | |||||||
ROW SHARE solicitado | Bloqueado | Bloqueado | ||||||
ROW EXCLUSIVE solicitado | Bloqueado | Bloqueado | Bloqueado | Bloqueado | ||||
SHARE UPDATE EXCLUSIVE solicitado | Bloqueado | Bloqueado | Bloqueado | Bloqueado | Bloqueado | |||
SHARE solicitado | Bloqueado | Bloqueado | Bloqueado | Bloqueado | Bloqueado | |||
SHARE ROW EXCLUSIVE solicitado | Bloqueado | Bloqueado | Bloqueado | Bloqueado | Bloqueado | Bloqueado | ||
EXCLUSIVE solicitado | Bloqueado | Bloqueado | Bloqueado | Bloqueado | Bloqueado | Bloqueado | Bloqueado | |
ACCESS EXCLUSIVE solicitado | Bloqueado | Bloqueado | Bloqueado | Bloqueado | Bloqueado | Bloqueado | Bloqueado | Bloqueado |
Bloqueios no nível de linha
Os bloqueios de nível de linha são mais granulares e só afetam outra transação que está acessando a mesma linha. Esse tipo de bloqueio aprimora a simultaneidade, mas adquirir e remover muitos bloqueios afeta negativamente o desempenho. Os bloqueios no nível da linha são adquiridos automaticamente pelo PostgreSQL e não são aplicados de modo manual.
Há quatro tipos de bloqueio de nível de linha no Banco de Dados do Azure para PostgreSQL e eles são adquiridos dependendo de quais outros tipos de bloqueio precisam ser bloqueados:
-- | FOR KEY SHARE existente | FOR SHARE existente | FOR NO KEY UPDATE existente | FOR UPDATE existente |
---|---|---|---|---|
FOR KEY SHARE solicitado | Bloqueado | |||
FOR SHARE solicitado | Bloqueado | Bloqueado | ||
FOR NO KEY UPDATE solicitado | Bloqueado | Bloqueado | Bloqueado | |
FOR UPDATE solicitado | Bloqueado | Bloqueado | Bloqueado | Bloqueado |
Bloqueios no nível de página
Os bloqueios no nível de página afetam uma página de dados, que normalmente consiste em várias linhas. Embora os processos do PostgreSQL usem bloqueios de nível de página, os desenvolvedores de aplicativos normalmente não exigem esse tipo de bloqueio.
Aplicar bloqueios manualmente e exibir bloqueios atuais
Para aplicar manualmente um bloqueio no nível de tabela, você pode usar o comando LOCK com o modo de bloqueio necessário. O comando LOCK precisa estar dentro de uma transação e os bloqueios são liberados quando a transação é concluída. Por exemplo:
BEGIN TRANSACTION;
LOCK TABLE humanresources.department IN ROW EXCLUSIVE MODE;
COMMIT;
Para exibir os bloqueios mantidos atualmente no banco de dados, use pg_locks. Por exemplo, para exibir todos os bloqueios atuais, use o seguinte comando:
SELECT * FROM pg_locks;