PostgreSQL: forza i dati in memoria


32

Esiste un modo sistematico per forzare PostgreSQL a caricare una tabella specifica in memoria o almeno a leggerla dal disco in modo che venga memorizzata nella cache dal sistema?

Risposte:


25

Potresti essere interessato a uno degli argomenti delle mailing list , è la risposta di Tom Lane (sviluppatore principale):

[..] Ma la mia opinione è che le persone che pensano di essere più intelligenti di un algoritmo di memorizzazione nella cache LRU sono in genere sbagliate. Se la tabella è molto utilizzata, rimarrà nella memoria bene. Se non è sufficientemente utilizzato per rimanere in memoria secondo un algoritmo LRU, forse lo spazio di memoria dovrebbe davvero essere speso per qualcos'altro. [..]

Potresti anche essere interessato a una domanda SO: https://stackoverflow.com/questions/486154/postgresql-temporary-tables e forse più adatto https://stackoverflow.com/questions/407006/need-to-load-the -Tutto-postgresql-Database-in-the-ram


1
+1 La stessa idea si applica anche ad altri RDBMS.
gbn,

25
Sì e no. Blocciamo alcune tabelle Oracle in memoria perché sappiamo che potrebbero non essere utilizzate così spesso, ma nella situazione in cui vengono utilizzate, la latenza sarà un killer. Un DB dovrebbe sempre dare la parola finale al DBA (un altro esempio sta suggerendo l'ottimizzatore delle query).
Gaius,

35

Postgres 9.4 ha infine aggiunto un'estensione per precaricare i dati dalle relazioni nel sistema operativo o nella cache del buffer del database (a scelta):

pg_prewarm

Ciò consente di raggiungere le prestazioni operative più rapidamente.

Esegui una volta nel database (istruzioni dettagliate qui ):

CREATE EXTENSION pg_prewarm;

Quindi è semplice precaricare qualsiasi relazione. Esempio di base:

SELECT pg_prewarm('my_tbl');

Trova la prima tabella denominata my_tblnel percorso di ricerca e la carica nella cache del buffer Postgres

O:

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

prefetchinvia richieste di prefetch asincrone al sistema operativo, se supportate, o genera un errore in caso contrario. read legge l'intervallo richiesto di blocchi; diversamente prefetch, questo è sincrono e supportato su tutte le piattaforme e build, ma potrebbe essere più lento. bufferlegge l'intervallo richiesto di blocchi nella cache del buffer del database.

L'impostazione predefinita è buffer, che ha il maggiore impatto (costo più elevato, migliore effetto).

Leggi il manuale per maggiori dettagli , le citazioni sono da lì.
Anche Depesz ne ha scritto un blog .


4

Nel caso generale, se si dispone di RAM sufficiente, in genere si può fidare del servizio di database per fare un buon lavoro nel mantenere le cose che si usano regolarmente nella RAM. Alcuni sistemi consentono di suggerire che la tabella deve essere sempre mantenuta nella RAM (che è utile per tabelle di piccole dimensioni che non vengono utilizzate spesso ma quando vengono utilizzate è importante che rispondano il più rapidamente possibile) ma se pgsql ha tali suggerimenti per la tabella devi stare molto attento a usarli poiché stai riducendo la quantità di memoria disponibile per la memorizzazione nella cache di qualsiasi altra cosa in modo da poter rallentare l'applicazione nel complesso.

Se stai cercando di adescare la cache della pagina del database all'avvio (ad esempio dopo un riavvio o un'altra operazione di mantenimento che fa dimenticare al DB tutto ciò che viene memorizzato nella cache), scrivi uno script che procede come segue:

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

(l'ultimo passaggio ripetuto per ciascun indice o corso e fare attenzione a disporre i campi nella clausola ORDER BY nell'ordine corretto)

Dopo aver eseguito quanto sopra ogni pagina di dati e indice dovrebbe essere stata letta e così sarà nella cache della pagina RAM (almeno per il momento). Abbiamo script come questo per i nostri database di applicazioni, che vengono eseguiti dopo il riavvio in modo che i primi utenti che accedono al sistema in seguito non abbiano una risposta più lenta. È meglio scrivere a mano uno di questi script, invece di scansionare le tabelle di definizione del db (come sys.objects/ sys.indexes/ sys.columnsin MSSQL), quindi puoi scansionare selettivamente gli indici che sono più comunemente usati piuttosto che scansionare tutto ciò che richiederà più tempo.


3
Questo non funzionerà, almeno su PostgreSQL. Un buffer ad anello piccolo (256 KB) viene allocato dai buffer condivisi per le scansioni sequenziali per impedire l'utilizzo dell'intera cache del buffer. Vedi github.com/postgres/postgres/blob/master/src/backend/storage/… per i dettagli. È possibile verificarlo eseguendo un SELECT * da una tabella di grandi dimensioni, quindi guardando la tabella pg_buffercache (dall'estensione pg_buffercache).
hbn,

@hbn ciao, ma questo tipo in questo thread di salvataggio dice che funziona - dba.stackexchange.com/a/36165/55752
scythargon

@scythargon potrebbe finire nella cache del sistema operativo, non lo troverà nella cache del buffer PostgreSQL. Prova quello che ho suggerito sopra se non mi credi.
hbn,

In Postgres 9.5, ho provato SELECT * FROM schema.tablee ho visto caricare l'intera tabella 60GiB nella mia cache buffer PostgreSQL 100GiB.
sudo

1

Ho avuto un problema simile:
dopo aver riavviato il servizio server e tutti i dati incassati sono caduti, molte query sono state chiamate la prima volta in cui erano davvero molto lente, a causa della complessità specifica delle query, fino a quando tutti gli indici e i dati necessari sono stati incassati. ciò significa, ad esempio, che gli utenti devono colpire una volta ogni "elemento" (1-3 secondi di esecuzione) e dati relativi da 50 milioni di righe, in modo che gli utenti non subiscano più ritardi indesiderati. Gli utenti impiegano le prime 3 ore a sperimentare fastidiosi blocchi, fino a quando i dati più utilizzati non vengono incassati e i programmi stanno rovinando il primato con le prestazioni di produzione, terminando anche allora, 2 giorni alcuni improvvisi ritardi brevi, quando colpiscono meno dati al primo accesso ... , per dati statistici ecc.

Per risolvere questo, ha scritto un piccolo script Python che esegue selezioni su tabelle utilizzate più pesanti con indici di grandi dimensioni. Ci sono voluti 15 minuti per l'esecuzione e nessun ritardo nelle prestazioni.


0

Hmmm, potrebbe essere il comando COPIA sarebbe d'aiuto. Basta eseguire COPY per stdout e leggere da esso. È possibile farlo usando pg_dump:

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

L'altro modo è trovare tutti i file della tabella ed eseguirli cat <files> > /dev/null.

Ecco l'esempio su come ottenere i nomi dei file delle tabelle:

# 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

quindi, i file della tabella sono / path / to / pgsql / data / base / 16384/24576 *

Ti piacerebbe leggere anche gli indici e le tabelle dei toast, ottenere il loro Oid allo stesso modo.

A proposito, perché ne hai bisogno? Credo che postgresql e il sistema operativo siano abbastanza intelligenti da memorizzare nella cache i dati più caldi e mantenerli in buono stato. efficienza della cache.


0

Io uso RAMDrive da QSoft, che è stato benchmark come il ramdisk più veloce per Windows. Ho appena usato

initdb -D e:\data

dove e: \ è il posto di RamDisk.


5
PG su Windows è una scelta piuttosto coraggiosa per un sito di produzione poiché è molto più lento su Windows rispetto a * nix (indipendente dalla RAM).
DrColossos,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.