web-dev-qa-db-fra.com

PostgreSQL: forcer les données en mémoire

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?

34
Adam Matan

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 SO question: https://stackoverflow.com/questions/486154/postgresql-temporary-tables et peut-être plus appropriée https://stackoverflow.com/questions/407006/need-to-load-the-whole-postgresql-database-into-the-ram

27
DrColossos

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');

Recherche la première table nommée my_tbl dans le chemin de recherche et le 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 plates-formes et versions, mais peut être plus lent. buffer lit 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 de là.
Depesz a blogué à ce sujet aussi.

39
Erwin Brandstetter

Dans le cas général, si vous en avez assez 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 le tableau doit toujours être conservé dans 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 devrait avoir été lue et se trouvera donc dans le RAM cache de page (pour le moment au moins). Nous avons des scripts comme celui-ci pour nos bases de données d'application, qui sont exécutées après le redémarrage afin que les premiers utilisateurs qui se connectent 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.columns dans MSSQL), vous pouvez alors analyser sélectivement les index les plus couramment utilisés plutôt que de scanner tout ce qui prendra plus de temps.

4
David Spillett

J'ai eu un problème similaire:
Après le redémarrage du service serveur et toutes les données encaissées ont été supprimées, de nombreuses requêtes appelées pour la première fois étaient vraiment très lentes, en raison de la complexité spécifique des requêtes, jusqu'à ce que tous les index et données nécessaires aient été 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 les plus lourdes utilisées avec de grands index. Il a fallu 15 minutes pour s'exécuter et aucun retard de performances.

1
LongBeard_Boldy

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

initdb -D e:\data

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

0
David

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 à 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.

0
rvs