Quel facteur de remplissage pour la mise en cache de la table?

10

J'ai une table fortement mise à jour / consultée où je stocke des objets java sérialisés. Ils sont dans le tableau pendant 2-3 heures (sont également mis à jour pendant cette période), puis supprimés. La taille de la table est d'environ 300 Mo. J'ai remarqué que c'est très, très souvent VIDE et je me demande si changer le fillfactorserait utile?

Michal
la source

Réponses:

17

Les mots clés ici sont:

  1. "fortement mis à jour"
  2. "dans le tableau pendant 2-3 heures".

Le point 1. indique un facteur de remplissage inférieur, tandis que 2. est le contraire. Il améliore les performances si plusieurs versions de lignes sont stockées sur la même page de données. Des mises à jour CHAUDES y parviendraient. Lisez ici ou ici . Ils ont besoin de marge de manœuvre sur la page de données - comme des tuples morts ou de l'espace réservé par un fillfactor<100. Mais ils ne peuvent faire leur travail que si aucun index n'implique l'une des colonnes mises à jour , ce qui devrait être vrai pour votre cas.

Un autre facteur important ici serait la taille du tuple (par rapport à la taille de votre page (qui est le plus souvent 8 Ko). Plus de détails dans cette réponse connexe:

Si la taille du tuple est de 4 ko ou plus, la réduction du facteur de remplissage serait futile, car il ne peut jamais y avoir plus d'un tuple sur une page de données. Vous pourriez aussi bien le laisser à 100(qui est de toute façon la valeur par défaut). Cependant, certains types de données sont "grillés" et stockés hors ligne s'ils dépassent une limite de taille, de sorte que les tuples nécessitant autant dans la fourchette de relation principale sont rares.

Quoi que vous fassiez, VACUUM sera exécuté souvent. Et c'est généralement une bonne chose, je ne m'en inquiéterais pas. Vous créez beaucoup de tuples morts. VACUUMidentifie les lignes mortes qui ne sont plus visibles par aucune transaction ouverte. Le manuel:

La forme standard de VACUUMsupprime les versions de lignes mortes dans les tables et les index et marque l'espace disponible pour une réutilisation future .

Accentuation sur moi.
Vous pouvez jouer avec les paramètres par table pour le vide automatique pour le déclencher moins (ou plus) souvent pour cette table uniquement:

Les seuils et facteurs d'échelle par défaut sont extraits de postgresql.conf, mais il est possible de les remplacer table par table ;

Accentuation sur moi. En particulier avec autovacuum_vacuum_thresholdetautovacuum_vacuum_scale_factor . Courir VACUUMbeaucoup pourrait en fait être une bonne idée, au lieu d'une très faible fillfacter. Cela dépend des modèles d'accès. Si tous les tuples vivent, disons, 3 heures et que chacun est mis à jour plusieurs fois, je baisserais toujours le fillfactorà quelque chose comme 50. Vous devrez tester et trouver le sweet spot.

Alternatives

Tout cela mis à part, car vos données semblent être volatiles pour commencer: utilisez un UNLOGGEDtableau :

Les données écrites dans des tables non enregistrées ne sont pas écrites dans le journal d'écriture anticipée (voir le chapitre 29 ), ce qui les rend considérablement plus rapides que les tables ordinaires. Cependant, ils ne sont pas protégés contre les pannes: une table non journalisée est automatiquement tronquée après un crash ou un arrêt impur. Le contenu d'une table non enregistrée n'est pas non plus répliqué sur les serveurs de secours.

Accentuation sur moi. Ne l'utilisez pas si votre serveur peut tomber en panne et que vous avez toujours besoin des données par la suite. Mais si nous parlons de données de session pour les applications Web, cela pourrait être un prix acceptable à payer.

Ou, encore plus radical: utilisez un magasin de valeurs-clés comme Redis si vous pouvez vous passer complètement des fonctionnalités et de la sécurité fournies par un SGBDR.

Erwin Brandstetter
la source
Je pense que UNLOGGED est exactement ce dont j'ai besoin
Michal
0

Je suggérerais un SGBD à valeur-clé, mais je le lance là-bas pour l'intérêt.

Au lieu d'exécuter des instructions INSERT & DELETE, effectuez uniquement des mises à jour.

La structure de la table sera quelque chose comme

ID      integer  -- sequential ID
Used    boolean  -- default FALSE
Object  -- whatever type is appropriate

La colonne contenant les objets sera de longueur fixe pour éviter les divisions et les déplacements de ligne. Dimensionnez cette colonne pour accueillir vos objets et remplir efficacement une page sur le disque.

Pré-remplissez votre tableau avec autant de lignes que vous en aurez besoin et quelques autres.

Lorsqu'un objet doit être écrit, recherchez une ligne avec Used = False et METTEZ À JOUR cette ligne. Lorsqu'un objet doit être détruit, réglez-le sur "Faux". Il n'y a pas de déchets créés et donc pas de collecte de déchets.

Bien sûr, il existe de très nombreuses conditions d'exception à gérer (débordement de ligne, débordement de table, conditions de concurrence sur l'utilisation des ID, etc.), mais aucune n'est insurmontable.

Michael Green
la source
Autant que je sache, ces MISES À JOUR écrivent généralement toujours une toute nouvelle copie de la ligne sur le disque, sauf s'il s'agit d'une mise à jour CHAUDE. Donc, vous finissez toujours par avoir besoin de GC / Vacuuming au fil du temps.
Jeff Widman