PostgreSQL: Forcer les données en mémoire

32

Existe-t-il un moyen systématique de forcer PostgreSQL à charger une table spécifique en mémoire, ou au moins à la lire à partir du disque afin qu'elle soit mise en cache par le système?

Adam Matan
la source

Réponses:

25

Vous pouvez être intéressé par l'un des sujets des listes de diffusion , il est répondu par Tom Lane (développeur principal):

[..] Mais mon opinion est que les gens qui pensent qu'ils sont plus intelligents qu'un algorithme de mise en cache LRU se trompent généralement. Si la table est très utilisée, elle restera bien en mémoire. S'il n'est pas suffisamment utilisé pour rester en mémoire selon un algorithme LRU, peut-être que l'espace mémoire devrait vraiment être dépensé pour autre chose. [..]

Vous pourriez également être intéressé par une question SO: /programming/486154/postgresql-temporary-tables et peut-être plus approprié /programming/407006/need-to-load-the -tout-postgresql-base de données-dans-le-bélier

Dr Colossos
la source
1
+1 La même idée s'applique également aux autres SGBDR.
gbn
25
Oui et non. Nous verrouillons certaines tables Oracle en mémoire car nous savons qu'elles peuvent ne pas être utilisées aussi souvent, mais dans la situation où elles sont utilisées, la latence sera un tueur. Une base de données doit toujours donner le dernier mot au DBA (un autre exemple fait allusion à l'optimiseur de requête).
Gaius
35

Postgres 9.4 a finalement ajouté une extension pour précharger les données des relations dans le cache du tampon du système d'exploitation ou de la base de données (à votre choix):

pg_prewarm

Cela permet d'atteindre plus rapidement la pleine performance opérationnelle.

Exécutez une fois dans votre base de données (instructions détaillées ici ):

CREATE EXTENSION pg_prewarm;

Il est ensuite simple de précharger une relation donnée. Exemple de base:

SELECT pg_prewarm('my_tbl');

my_tblRecherche la première table nommée dans le chemin de recherche et la charge dans le cache du tampon Postgres

Ou:

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

prefetchémet des demandes de prélecture asynchrones vers le système d'exploitation, si cela est pris en charge, ou génère une erreur dans le cas contraire. read lit la plage de blocs demandée; contrairement à prefetch, il est synchrone et pris en charge sur toutes les plateformes et versions, mais peut être plus lent. bufferlit la plage de blocs demandée dans le cache de tampon de la base de données.

La valeur par défaut est buffer, qui a le plus grand impact (coût plus élevé, meilleur effet).

Lisez le manuel pour plus de détails , les citations sont là.
Depesz a également blogué à ce sujet.

Erwin Brandstetter
la source
4

Dans le cas général, si vous avez suffisamment de RAM, vous pouvez généralement faire confiance au service de base de données pour bien conserver les éléments que vous utilisez régulièrement en RAM. Certains systèmes vous permettent d'indiquer que la table doit toujours être conservée en RAM (ce qui est utile pour les petites tables qui ne sont pas souvent utilisées mais quand elles sont utilisées, il est important qu'elles répondent le plus rapidement possible) mais si pgsql a de telles indications de table vous devez être très prudent lorsque vous les utilisez, car vous réduisez la quantité de mémoire disponible pour la mise en cache de quoi que ce soit d'autre afin de ralentir globalement votre application.

Si vous cherchez à amorcer le cache des pages de la base de données au démarrage (par exemple après un redémarrage ou une autre opération de maintenance qui fait que la base de données oublie tout ce qui est mis en cache), écrivez un script qui fait ce qui suit:

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

(cette dernière étape est répétée pour chaque index ou cours, et veillez à ce que les champs de la clause ORDER BY soient dans le bon ordre)

Après avoir exécuté ce qui précède, chaque page de données et d'index doit avoir été lue et sera donc dans le cache de page RAM (pour le moment au moins). Nous avons des scripts comme celui-ci pour nos bases de données d'application, qui sont exécutés après le redémarrage afin que les premiers utilisateurs se connectant au système par la suite ne connaissent pas une réactivité plus lente. Il vaut mieux écrire à la main un tel script, au lieu d'analyser les tables de définition de la base de données (comme sys.objects/ sys.indexes/ sys.columnsdans MSSQL), alors vous pouvez analyser sélectivement les index les plus couramment utilisés plutôt que d'analyser tout ce qui prendra plus de temps.

David Spillett
la source
3
Cela ne fonctionnera pas, du moins sur PostgreSQL. Un petit tampon en anneau (256 Ko) est alloué à partir des tampons partagés pour des analyses séquentielles afin d'empêcher l'utilisation de la totalité du cache de tampon. Voir github.com/postgres/postgres/blob/master/src/backend/storage/… pour les détails. Vous pouvez le vérifier en faisant un SELECT * à partir d'une grande table puis en regardant la table pg_buffercache (à partir de l'extension pg_buffercache).
hbn
@hbn bonjour là-bas, mais ce gars dans ce fil de sauvegarde dit que cela fonctionne - dba.stackexchange.com/a/36165/55752
scythargon
@scythargon il pourrait se retrouver dans le cache du système d'exploitation, il ne l'aura pas dans le cache du tampon PostgreSQL. Essayez ce que j'ai suggéré ci-dessus si vous ne me croyez pas.
hbn
Dans Postgres 9.5, j'ai essayé SELECT * FROM schema.tableet je l'ai vu charger la table 60GiB entière dans mon cache tampon PostgreSQL 100GiB.
sudo
1

J'ai eu un problème similaire:
après le redémarrage du service serveur et toutes les données encaissées ont été abandonnées, de nombreuses requêtes appelées la première fois étaient vraiment très lentes, à cause de la complexité spécifique des requêtes, jusqu'à ce que tous les index et données nécessaires soient encaissés. cela signifie, par exemple, que les utilisateurs doivent frapper une fois chaque "élément" (temps d'exécution de 1 à 3 secondes) et les données associées de 50 millions de lignes, afin que les utilisateurs ne subissent plus de retards indésirables. Il faut 3 heures pour que les utilisateurs éprouvent des blocages ennuyeux, jusqu'à ce que la plupart des données utilisées soient encaissées et que les programmes ruinent les performances de production, même après, 2 jours quelques courts délais soudains, lorsque vous frappez moins de données accédées pour la première fois ... , pour les données statistiques, etc.

Pour résoudre ce problème, nous avons écrit un petit script python qui effectue des sélections sur les tables utilisées les plus lourdes avec de grands index. Il a fallu 15 minutes pour fonctionner et aucun retard de performance.

LongBeard_Boldy
la source
0

Hmmm, la commande COPY pourrait être utile. Exécutez simplement COPY sur stdout et lisez-le. Il est possible de le faire en utilisant pg_dump:

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

Une autre méthode consiste à rechercher tous les fichiers de table et à les exécuter cat <files> > /dev/null.

Voici l'exemple sur la façon d'obtenir des noms de fichiers de table:

# 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

ainsi, le (s) fichier (s) de la table est / path / to / pgsql / data / base / 16384/24576 *

Vous devez également lire les index et les tables de toast, obtenir leurs oids de la même manière.

BTW, pourquoi en avez-vous besoin? Je crois que postgresql et OS sont assez intelligents pour mettre en cache les données les plus chaudes et maintenir une bonne qualité. efficacité du cache.

rvs
la source
0

J'utilise RamDrive de QSoft, qui a été évalué comme le disque virtuel le plus rapide pour Windows. Je viens d'utiliser

initdb -D e:\data

où e: \ est l'emplacement du RamDisk.

David
la source
5
PG sur Windows est un choix assez courageux pour un site de production car il est beaucoup plus lent sur Windows que sur * nix (indépendant de la RAM).
DrColossos