Menu

SQLite In-Memory: Banco de Dados na RAM com :memory:

Como funciona o banco de dados em memória do SQLite, quando vale a pena usar :memory: e o que muda em relação a um banco salvo em arquivo.

Esta página tem editores executáveis — edite, execute e veja a saída na hora.

Um banco de dados que vive na RAM

O SQLite tem um nome de arquivo especial: :memory:. Ao abrir um banco com esse nome, o SQLite ignora completamente o disco — todo o banco fica na RAM. Tabelas, índices, transações, chaves estrangeiras, tudo funciona exatamente igual. A única diferença é que, quando a conexão é fechada, o banco some.

Pela linha de comando:

sqlite3 :memory:

Pronto, agora você está no prompt do SQLite com um banco em memória zerado, totalmente vazio. Daqui pra frente é tudo igual: cria uma tabela, insere algumas linhas, faz consultas — exatamente como você já faz no dia a dia:

Encerre a sessão e esses dados evaporam. Não sobra arquivo nenhum, porque nenhum arquivo chegou a ser criado.

Quando faz sentido usar

Um banco que não sobrevive a um restart parece bug, não feature. Mas existem três cenários em que isso é exatamente o que você quer.

Testes. Cada teste recebe um banco limpinho em milissegundos. Sem precisar limpar arquivos temporários, sem estado residual da execução anterior, sem aquele fixture compartilhado travando. A maioria das suítes de teste em Python, Node e Go que usam SQLite abre :memory: justamente por isso.

Análise descartável. Carregue um CSV, rode algumas queries, descarte. É mais rápido do que subir um banco de verdade e mais prático do que ficar parseando o arquivo no código toda vez.

Cache e área de rascunho. Dentro de um programa que roda por muito tempo, um banco SQLite em memória vira uma engine de consulta ad-hoc surpreendentemente boa para dados que você já carregou.

O ponto em comum: você quer SQL, mas não quer persistência.

Performance: mais rápido, mas não é mágica

O modo in-memory do SQLite pula o disco, então escritas que normalmente iriam para o sistema de arquivos viram só atualizações de memória. Cargas de trabalho limitadas por I/O ficam visivelmente mais rápidas. Já as limitadas por CPU — planejamento complexo de queries, ordenações grandes — praticamente não mudam, porque o SQLite já mantinha as páginas quentes em memória de qualquer jeito.

Veja como a sintaxe é idêntica à de um banco em arquivo:

Esse exemplo rodou em um banco de dados em memória, mas é exatamente o mesmo SQL que você usaria em um banco em arquivo. O motor do banco não faz distinção.

SQLite in memory vs arquivo: quando usar cada um

O trade-off é simples, e vale deixar claro:

  • Banco em arquivo (mydata.db): Persiste entre reinicializações. Vários processos podem abrir o mesmo arquivo. Sobrevive a quedas (com modo WAL, na maior parte dos casos). Use sempre que precisar guardar informação de verdade.
  • Banco em memória (:memory:): Some quando a conexão é fechada. Por padrão, fica restrito à conexão que o abriu. Mais rápido para cargas de escrita descartáveis. Ideal para testes, rascunhos e caches de curta duração.

Na dúvida, vá de arquivo. O banco em memória é o caso especial.

Cada conexão cria seu próprio banco

Tem um detalhe sutil que pega muita gente: abrir :memory: duas vezes resulta em dois bancos completamente separados. Eles não compartilham tabelas, não compartilham dados e nem enxergam um ao outro.

-- Terminal 1
sqlite3 :memory:
sqlite> CREATE TABLE t (x); INSERT INTO t VALUES (1);

-- Terminal 2
sqlite3 :memory:
sqlite> SELECT * FROM t;
Error: no such table: t

Não é um bug — é assim que foi projetado. :memory: quer dizer "um banco privado para esta conexão". O mesmo vale dentro de um único programa: se o seu código abre duas conexões para :memory:, cada uma terá seu próprio banco isolado.

Compartilhando um banco SQLite em memória entre conexões

Se você precisa que várias conexões enxerguem o mesmo banco SQLite em memória, dá para fazer isso usando nomes de arquivo no formato URI junto com o cache compartilhado. A string mágica é file::memory:?cache=shared:

sqlite3 'file::memory:?cache=shared'

Qualquer conexão no mesmo processo que abrir essa URI exata se conecta ao mesmo banco. Quando todas forem fechadas, o banco desaparece.

Você também pode dar um nome ao banco de dados em memória, o que é útil quando precisa de vários bancos compartilhados distintos:

sqlite3 'file:mydb?mode=memory&cache=shared'

O nome mydb aqui é só um rótulo — continua não existindo arquivo nenhum. Duas conexões que abrem file:mydb?mode=memory&cache=shared compartilham o mesmo banco; já uma conexão que abre file:other?mode=memory&cache=shared cai em outro banco diferente.

Como salvar um banco SQLite em memória no disco

Às vezes você faz todo o trabalho em memória e, no fim, decide que quer guardar o resultado. A CLI tem um dot-command .backup justamente para isso:

sqlite3 :memory:
sqlite> CREATE TABLE results (id INTEGER, score REAL);
sqlite> INSERT INTO results VALUES (1, 0.91), (2, 0.87);
sqlite> .backup snapshot.db
sqlite> .quit

snapshot.db agora é um banco em arquivo comum, com exatamente o mesmo conteúdo. Dá pra abrir depois com sqlite3 snapshot.db e continuar de onde parou.

O caminho inverso também funciona — o .restore carrega um banco em arquivo para a memória da conexão atual:

sqlite3 :memory:
sqlite> .restore snapshot.db
sqlite> SELECT * FROM results;

No código da aplicação, a API C do SQLite expõe o mesmo mecanismo via sqlite3_backup_init, e a maioria dos bindings de linguagens faz um wrapper em cima disso. O módulo sqlite3 do Python, por exemplo, traz o método Connection.backup().

Uma armadilha comum

Vez ou outra, o pessoal tenta "salvar" um banco SQLite em memória anexando um arquivo e copiando os dados na mão:

Isso funciona para cópias simples de tabela, mas não preserva índices, triggers, views ou foreign keys exatamente como estavam. Para uma cópia fiel do banco inteiro, use .backup (ou a backup API) — ela faz uma cópia binária precisa no nível das páginas.

O que fica de bagagem

  • :memory: é um nome de arquivo especial do SQLite que cria um banco de dados em RAM, sem nenhum arquivo por trás.
  • O SQL é idêntico ao de um banco em arquivo — mesmas tabelas, mesmas queries, mesmas constraints.
  • Cada conexão com :memory: é privada; use URIs de cache compartilhado (file::memory:?cache=shared) quando várias conexões precisarem compartilhar o mesmo banco.
  • É a ferramenta certa para testes, análises descartáveis e caches de vida curta — não para nada que precise sobreviver a um restart.
  • Quando decidir que vale a pena guardar, promova o banco em memória para o disco com .backup.

A seguir: criando tabelas

Você já viu o CREATE TABLE aparecer rapidinho em alguns exemplos. A próxima página dá uma freada e mostra ele direito — definições de colunas, tipos, as constraints que dá pra encaixar e as pequenas decisões que tornam um schema agradável de conviver no dia a dia.

Perguntas frequentes

Como criar um banco de dados SQLite em memória?

Em vez de passar o caminho de um arquivo, abra o SQLite com o nome especial :memory:. No CLI fica sqlite3 :memory:; em qualquer biblioteca, é só usar :memory: como nome do arquivo na chamada de conexão. O banco vive na RAM e some assim que você fecha a conexão.

O que é :memory: no SQLite?

:memory: é um nome de arquivo "mágico" que o SQLite reconhece como: "esquece o disco, deixa tudo na RAM". Você tem um banco SQLite completo — tabelas, índices, transações, tudo igual —, só que nada é gravado em disco. E mais: cada conexão que abre :memory: ganha o seu próprio banco, isolado dos outros.

Duas conexões podem compartilhar o mesmo banco em memória?

Por padrão não — cada :memory: é isolado da sua conexão. Para compartilhar, abra usando uma URI tipo file::memory:?cache=shared com o cache compartilhado habilitado. Aí, todas as conexões que abrirem essa mesma URI dentro do processo enxergam o mesmo banco.

Dá para salvar um banco SQLite em memória no disco?

Dá sim. No CLI, use o comando .backup para copiar o banco em memória para um arquivo; nas bibliotecas, existe a API de backup que faz a mesma coisa. Outra opção é usar ATTACH para anexar um banco em arquivo e rodar algo como INSERT INTO arquivo.tabela SELECT * FROM main.tabela para mover os dados.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR