Estou lendo um livro sobre bancos de dados e um capítulo dele fala sobre o gerenciador de buffer e suas estratégias de substituição.
Percebi que o DBMS interage diretamente com a memória, em vez de solicitar que o SO interaja com a memória virtual. Isso é correto? Como exatamente essa comunicação direta ocorre? Quanta memória o DBMS pode alocar? Eu nunca fui exposto a chamadas de função de baixo nível e adoraria ver algumas explicações e exemplos disso.
Obter esse tipo de informação é meio complicado de encontrar no google se você não souber as palavras-chave corretas para pesquisar.
Vamos falar sobre MySQL/MariaDB apenas com ENGINE=InnoDB. (Esse é praticamente o único mecanismo em uso hoje.)
Portanto, é muito importante dar ao InnoDB a maior parte da RAM e deixá-lo fazer o seu trabalho. Uma regra simples:
innodb_buffer_pool_size
deve ser definido para cerca de 70% da RAM. Para a maioria dos aplicativos, essa é a configuração mais importante e a única que precisa ser alterada do padrão.Definir o buffer_pool muito grande pode levar à troca. Mas, como o InnoDB o trata como um grande array, isso pode causar uma quantidade terrível de trocas, diminuindo a velocidade do MySQL/MariaDB terrivelmente.
O InnoDB possui threads para leitura de blocos de escrita. Em particular, a descarga para o disco é um pouco feita "em segundo plano". Isso permite que um
INSERT
pareça ser mais rápido do que realmente é.Eu discuto a alocação de memória mais adiante aqui
Usar "memória virtual" para acessar um arquivo é uma maneira preguiçosa de fazer as coisas. Funciona bem para casos simples. No entanto, um mecanismo de banco de dados precisa ser eficiente e rápido. Quando o código conhece o padrão de acesso, é melhor usar um método de acesso ajustado para tal.
Por exemplo, se você for ler um arquivo sequencialmente, é melhor (para gerenciamento de memória) fazer ping-ping entre dois buffers 'pequenos'; um sendo lido e um sendo analisado. (Um único buffer "circular" é uma boa alternativa.)
Como tudo está em blocos de 16KB, existe um número que identifica exclusivamente tal. É bastante grande (20? bytes). Inclui pelo menos o número do "tablespace" e o número do bloco dentro do tablespace. Isso é tomado como módulo do número de buffer_pool_instances para decidir em qual instância procurar.
Dentro de um bloco, existem linhas da tabela ou linhas de um índice secundário, ou linhas de um nó na B+Tree (ver Wikipedia) que ele representa.
Se o bloco não estiver no buffer_pool, ele deverá aguardar enquanto ocorre uma leitura. Mas, antes que a leitura possa ocorrer, pode ser necessário haver uma gravação para liberar algum bloco. Normalmente, um thread em segundo plano libera blocos "sujos" para que sempre haja alguns blocos livres no buffer_pool. ("Grátis" ou "facilmente removidos" porque não estão sujos.)