PostgreSQL: força os dados na memória

32

Existe uma maneira sistemática de forçar o PostgreSQL a carregar uma tabela específica na memória ou, pelo menos, lê-la do disco para que seja armazenada em cache pelo sistema?

Adam Matan
fonte

Respostas:

25

Você pode se interessar em um dos tópicos das listas de discussão , é respondido por Tom Lane (desenvolvedor principal):

[..] Mas minha opinião é que as pessoas que pensam que são mais inteligentes que um algoritmo de cache LRU geralmente estão enganadas. Se a tabela for muito usada, ela permanecerá na memória muito bem. Se não for usado o suficiente para permanecer na memória de acordo com um algoritmo LRU, talvez o espaço na memória deva ser realmente gasto em outra coisa. [..]

Você também pode se interessar por uma pergunta do SO: https://stackoverflow.com/questions/486154/postgresql-temporary-tables e talvez mais adequado https://stackoverflow.com/questions/407006/need-to-load-the -whole-postgresql-database-into-the-ram

DrColossos
fonte
1
+1 A mesma idéia se aplica a outros RDBMS também.
GBN
25
Sim e não. Bloqueamos algumas tabelas Oracle na memória porque sabemos que elas podem não ser usadas com tanta frequência, mas, na situação em que são usadas, a latência será um fator decisivo. Um banco de dados deve sempre dar a palavra final ao DBA (outro exemplo é sugerir o otimizador de consulta).
Caio
35

O Postgres 9.4 finalmente adicionou uma extensão para pré-carregar dados de relações no cache do buffer do SO ou do banco de dados (a sua escolha):

pg_prewarm

Isso permite alcançar o desempenho operacional completo mais rapidamente.

Execute uma vez no seu banco de dados (instruções detalhadas aqui ):

CREATE EXTENSION pg_prewarm;

Então é simples pré-carregar qualquer relação. Exemplo básico:

SELECT pg_prewarm('my_tbl');

Localiza a primeira tabela nomeada my_tblno caminho de pesquisa e a carrega no cache do buffer do Postgres

Ou:

SELECT pg_prewarm('my_schema.my_tbl', 'prefetch');

prefetchemite solicitações de pré-busca assíncrona para o sistema operacional, se houver suporte, ou gera um erro caso contrário. read lê o intervalo solicitado de blocos; ao contrário prefetch, isso é síncrono e suportado em todas as plataformas e compilações, mas pode ser mais lento. bufferlê o intervalo de blocos solicitado no cache do buffer do banco de dados.

O padrão é o bufferque tem o maior impacto (custo mais alto, melhor efeito).

Leia o manual para mais detalhes , as citações são de lá.
Depesz também escreveu em seu blog .

Erwin Brandstetter
fonte
4

No caso geral, se você tiver RAM suficiente, geralmente pode confiar no serviço de banco de dados para fazer um bom trabalho em manter as coisas que você usa regularmente na RAM. Alguns sistemas permitem sugerir que a tabela sempre deve ser mantida na RAM (o que é útil para tabelas pequenas que não são usadas com frequência, mas quando são usadas, é importante que respondam o mais rápido possível), mas se o pgsql tiver essas dicas de tabela você precisa ter muito cuidado ao usá-los, pois reduz a quantidade de memória disponível para armazenar em cache qualquer outra coisa, para que você possa desacelerar o aplicativo em geral.

Se você deseja preparar o cache da página do banco de dados na inicialização (por exemplo, após uma reinicialização ou outra operação de manutenção que faz com que o banco de dados esqueça tudo o que é armazenado em cache), escreva um script que faça o seguinte:

SELECT * FROM <table>
SELECT <primary key fields> FROM <table> ORDER BY <primary key fields>
SELECT <indexed fields> FROM <table> ORDER BY <indexed fields>

(essa última etapa foi repetida para cada índice ou curso e tenha o cuidado de ter os campos na cláusula ORDER BY na ordem correta)

Após a execução do procedimento acima, todas as páginas de dados e índice deveriam ter sido lidas e, portanto, estarão no cache da página de RAM (por enquanto, pelo menos). Temos scripts como este para nossos bancos de dados de aplicativos, que são executados após a reinicialização, para que os primeiros usuários que efetuam login no sistema depois não tenham uma resposta mais lenta. É melhor escrever manualmente esse script, em vez de varrer as tabelas de definição de banco de dados (como sys.objects/ sys.indexes/ sys.columnsno MSSQL), e então você pode varrer seletivamente os índices mais usados, em vez de varrer tudo o que levará mais tempo.

David Spillett
fonte
3
Isso não vai funcionar, pelo menos no PostgreSQL. Um pequeno buffer de anel (256 KB) é alocado a partir de buffers compartilhados para varreduras sequenciais para impedir que todo o cache do buffer seja usado. Veja github.com/postgres/postgres/blob/master/src/backend/storage/… para obter detalhes. Você pode verificar isso fazendo um SELECT * a partir de uma tabela grande e olhando para a tabela pg_buffercache (da extensão pg_buffercache).
hbn 14/07
@hbn Olá lá, mas esse sujeito cara neste economias fio diz que ele funciona - dba.stackexchange.com/a/36165/55752
scythargon
@scythargon pode acabar no cache do SO, não o conseguirá no cache do PostgreSQL. Experimente o que sugeri acima, se você não acredita em mim.
Hbn
No Postgres 9.5, tentei SELECT * FROM schema.tablee vi carregar toda a tabela 60GiB no meu cache de buffer 100GiB PostgreSQL.
Sudo
1

Eu tive um problema semelhante:
depois de reiniciar o serviço do servidor e todos os dados descontados caírem, muitas consultas foram iniciadas na primeira vez em que são realmente lentas, causa de complexidade específica das consultas, até que todos os índices e dados necessários foram descontados. isso significa que, por exemplo, os usuários precisam acessar uma vez a cada "item" (1 a 3 segundos de execução) e dados relacionados de 50 milhões de linhas, para que os usuários não sofram mais atrasos indesejados. Leva três primeiras horas para que os usuários experimentem travamentos irritantes, até que a maioria dos dados usados ​​seja descontada e os programas estejam arruinando o melhor do desempenho da produção, terminando mesmo assim, 2 dias com alguns atrasos bruscos repentinos, ao obter menos dados acessados ​​pela primeira vez ... , para dados estatísticos etc.

Para resolver isso, escrevi um pequeno script python que executa seleções nas tabelas mais pesadas usadas com índices grandes. Demorou 15 minutos para ser executado e sem atrasos no desempenho.

LongBeard_Boldy
fonte
0

Hmmm, pode ser o comando COPY ajudaria. Basta executar COPY para stdout e ler a partir dele. É possível fazer isso usando pg_dump:

pg_dump -U <user> -t <table> <database> > /dev/null

Outra maneira é encontrar todos os arquivos de tabela e executar cat <files> > /dev/null.

Aqui está o exemplo de como obter nomes de arquivos de tabela:

# SELECT oid, datname FROM pg_database ;
  oid  |  datname  
-------+-----------                                                                                                                                          
<...>
 16384 | test
-- out of database is 16384
# SELECT oid, relname FROM pg_class WHERE relname like 'fn%';
  oid  | relname 
-------+---------
 24576 | fn
(1 row)
-- oid of our table is 24576

portanto, o (s) arquivo (s) da tabela é / path / to / pgsql / data / base / 16384/24576 *

Você também pode ler índices e tabelas de brinde, obter seus oids da mesma maneira.

BTW, por que você precisa? Acredito que o postgresql e o SO sejam inteligentes o suficiente para armazenar em cache os dados mais quentes e manter bons. eficiência de cache.

rvs
fonte
0

Eu uso o RamDrive da QSoft, que foi comparado como o ramdisk mais rápido do Windows. Eu apenas usei

initdb -D e:\data

onde e: \ é o local do RamDisk.

David
fonte
5
O PG no Windows é uma escolha bastante corajosa para um site de produção, pois é muito mais lento no Windows do que no * nix (independente da RAM).
DrColossos