Detalhes sobre Lock de Tabelas
O código de bloqueio de tabelas no MariaDB é livre de deadlock.
O MariaDB utiliza bloqueio de tabelas (no lugar de bloqueio de registros ou colnas) em todos os tipos de tabelas, exceto tabelas BDB
, para obter uma alta velocidade nos bloqueios. Para grandes tabelas, bloqueio de tabelas é MUITO melhor que bloqueio de registros para a maioria das aplicações, mas existem, é claro, algumas desvantagens.
Para tabelas BDB
e InnoDB
, O MariaDB só utiliza bloqueio de tabelas se você bloquear explicitamente a tabela com LOCK TABLES
ou executar um comando quer irá modificar todos os registros na tabela, como ALTER TABLE
. Para estes tipos de tabelas nós recomendamos a você não utilizar LOCK TABLES
.
No MariaDB versão 3.23.7 ou superior , você pode inserir registros em tabelas MyISAM
ao mesmo tempo que outras threads estão lendo da mesma tabela. Perceba que atualmente isto funciona somente se não existirem buracos depois de registros apagados na tabela no momento que a inserção é feita. Quando todos os buracos forem preenchidos com novos dados, inserções concorrentes irão automaticamente ser habilitadas novamente.
O bloqueio de tabelas habilita várias threads para lerem de uma tabela ao mesmo tempo, mas se uma thread desejar escrever a uma tabela, ela primeiramente deve obter acesso exclusivo. Durante a atualização, todas outras threads que desejarem acessar esta tabela em particular irão esperar até que a atualização acabe.
Como atualizações em tabelas normalmente são consideradas mais importantes que SELECT
, todas as instruções que atualizam uma tabela tem maior prioridade que instruções que simplesmente recuperam informações. Isto deve garantir que atualizações não fiquem na fila por terem sido passadas várias consultas pesadas em uma tabela específica. (Você pode alterar isto utilizando LOW_PRIORITY com a instrução que faz a atualização ou HIGH_PRIORITY
com a instrução SELECT
.)
A partir do MariaDB versão 3.23.7 pode-se utilizadar a variável max_write_lock_count
para forçar o MariaDB a fornecer temporariamente a todas as instruções SELECT
, que esperam por uma tabela, uma prioridade mais alta depois de um número específico de inserções em uma tabela.
O bloqueio de tabela não é, no entanto, muito bom sobre os seguintes cenários:
- Um cliente emite uma
SELECT
que exige muito tempo para ser executada. - Outro cliente então executa um
UPDATE
na tabela usada. Este cliente terá que esperar até que aSELECT
seja terminada. - Outro cliente executa outra instrução
SELECT
na mesma tabela. ComoUPDATE
tem maior prioridade queSELECT
, estaSELECT
irá esperar pelo término daUPDATE
. Ela também irá esperar pelo término da primeiraSELECT
! - Uma thread está esperando por algo do tipo
disco cheio
, caso em que todas as threads que desejam acessar a tabela com problema irão ser colocadas em estado de espera até que mais espaço em disco seja disponível.
Algumas soluções possíveis para este problema são:
- Tente deixar suas instruções
SELECT
sempre rápidas. Você pode ter que criar algumas tabelas de resumo para fazer isto. - Inicie o
mysqld
com--low-priority-updates
. Isto irá fornecer a todas instruções que atualizam (modificam) uma tabela prioridade menor que uma instruçãoSELECT
. Neste caso a última instruçãoSELECT
no cenário anterior deveria executar antes da instruçãoINSERT
.Você pode fornecer a uma instrução
INSERT
,UPDATE
ouDELETE
específica menor prioridade com o atributoLOW_PRIORITY
. - Inicie o
mysqld
com um valor baixo para max_write_lock_count para fornecer bloqueios deLEITURA
depois de um certo número de bloqueios deESCRITA
. - Você pode especificar que todas as atualizações de uma thread específica deve ser feita utilizando prioridade baixa com o comando SQL:
SET SQL_LOW_PRIORITY_UPDATES=1
. Leia "Sintaxe deSET
". - Você pode especificar que uma
SELECT
específica é muito importante com o atributoHIGH_PRIORITY
. Leia "SintaxeSELECT
". - Se você tiver problemas com
INSERT
combinado comSELECT
, utilize as novas tabelasMyISAM
, pois elas suportamSELECT
s eINSERT
s concorrentes. - Se você utiliza principalmente instruções
INSERT
eSELECT
misturadas, o atributoDELAYED
noINSERT
provavelmente irá resolver seus problemas. Leia "SintaxeINSERT
". - Se você tiver problemas com
SELECT
eDELETE
, a opçãoLIMIT
paraDELETE
pode ajudar. Leia "SintaxeDELETE
".