Récemment, j'ai eu un serveur PostgreSQL 8.2.11 mis à niveau vers 8.4 afin de profiter des fonctionnalités d'autovacuum et d'être en ligne avec 30 autres autres serveurs PGSQL. Cela a été fait par un groupe informatique distinct qui gère le matériel, nous n'avons donc pas beaucoup de choix sur les autres mises à niveau (ne verront pas 9+ pendant un certain temps). Le serveur existe dans un environnement très fermé (réseau isolé, privilèges root limités) et fonctionne sur RHEL5.5 (i686). Après la mise à niveau, la base de données a constamment augmenté de 5 à 6 Go par jour. Normalement, la base de données dans son ensemble est d'environ 20 Go; actuellement, il est d'environ 89 Go. Nous avons quelques autres serveurs qui exécutent des bases de données équivalentes et synchronisent réellement les enregistrements entre eux via une application tierce (dont je n'ai pas accès aux rouages internes). Les autres bases de données font ~ 20 Go comme il se doit.
En exécutant le SQL suivant, il est assez évident qu'il y a un problème avec une table particulière et, plus spécifiquement, sa table TOAST.
SELECT nspname || '.' || relname AS "relation",
pg_size_pretty(pg_relation_size(C.oid)) AS "size"
FROM pg_class C
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
ORDER BY pg_relation_size(C.oid) DESC
LIMIT 20;
Ce qui produit:
relation | Taille ------------------------------------ + --------- pg_toast.pg_toast_16874 | 89 Go fews00.warmstates | 1095 Mo ... (20 rangées)
Cette table TOAST est destinée à une table appelée "timeseries" qui enregistre de gros enregistrements de données blobées. Un SUM(LENGTH(blob)/1024./1024.)
de tous les enregistrements de la série temporelle donne ~ 16 Go pour cette colonne. Il ne devrait y avoir aucune raison que la table TOAST de cette table soit aussi grande qu'elle l'est.
J'ai effectué un VACUUM FULL VERBOSE ANALYZE timeseries
, et le vide se termine sans erreur.
INFO: passer l'aspirateur "pg_toast.pg_toast_16874"
INFO: "pg_toast_16874": trouvé 22483 versions amovibles, 10475318 non amovibles en 10448587 pages
DÉTAIL: aucune version de ligne morte ne peut encore être supprimée.
Les versions de ligne non amovibles ont une longueur de 37 à 2036 octets.
Il y avait 20121422 pointeurs d'article inutilisés.
L'espace libre total (y compris les versions de lignes amovibles) est de 0 octet. 4944885 pages sont ou deviendront vides, y compris 0 à la fin du tableau. 4944885 pages contenant 0 octets libres sont des destinations de déplacement potentielles.
CPU 75.31s / 29.59u sec écoulé 877.79 sec.
INFO: l'index "pg_toast_16874_index" contient désormais 10475318 versions de lignes sur 179931 pages.
DÉTAIL: 23884 versions de lignes d'index ont été supprimées.
Les pages d'index 101623 ont été supprimées, 101623 sont actuellement réutilisables.
CPU 1.35s / 2.46u sec écoulé 21.07 sec.
REINDEXer la table qui a libéré un certain espace (~ 1 Go). Je ne peux pas CLUSTER la table car il n'y a pas assez d'espace sur le disque pour le processus, et j'attends de reconstruire la table entièrement car j'aimerais savoir pourquoi elle est tellement plus grande que les bases de données équivalentes que nous avons.
Exécutez une requête du wiki PostgreSQL ici - "Afficher la base de données Bloat" , et voici ce que j'obtiens:
base de données_actuelle | schemaname | nom_table | tbloat | wastedbytes | iname | ibloat | gaspillages ----------------- + ------------ + ------------------- ------------- + -------- + ------------- + ------------- -------------------- + -------- + -------------- ptrdb04 | fews00 | timeseries | 1.0 | 0 | idx_timeseries_synchlevel | 0,0 | 0 ptrdb04 | fews00 | timeseries | 1.0 | 0 | idx_timeseries_localavail | 0,0 | 0 ptrdb04 | fews00 | timeseries | 1.0 | 0 | idx_timeseries_expirytime | 0,0 | 0 ptrdb04 | fews00 | timeseries | 1.0 | 0 | idx_timeseries_expiry_null | 0,0 | 0 ptrdb04 | fews00 | timeseries | 1.0 | 0 | uniq_localintid | 0,0 | 0 ptrdb04 | fews00 | timeseries | 1.0 | 0 | pk_timeseries | 0,1 | 0 ptrdb04 | fews00 | idx_timeseries_expiry_null | 0,6 | 0 | ? | 0,0 | 0
Il semble que la base de données ne considère pas du tout cet espace comme "vide", mais je ne vois tout simplement pas d'où vient tout l'espace disque!
Je soupçonne que ce serveur de base de données décide d'utiliser 4 à 5 fois plus d'espace disque pour enregistrer les mêmes enregistrements extraits des autres serveurs de données. Ma question est la suivante: existe-t-il un moyen de vérifier la taille du disque physique d'une ligne? Je voudrais comparer la taille d'une ligne de cette base de données à une autre base de données "saine".
Merci pour toute l'aide que vous pourrez fournir!
MISE À JOUR 1
J'ai fini par reconstruire la table à partir d'un schéma vidé en raison de sa taille (je ne pouvais pas la laisser seule un autre jour). Après avoir synchronisé les données, via le processus de synchronisation du logiciel, la table TOAST était ~ 35 Go; cependant, je ne pouvais en représenter que 9 Go à partir de cette colonne blob qui devrait être la plus longue en termes de valeurs. Je ne sais pas d'où vient l'autre 26 Go. CLUSTERed, VACUUM FULLed et REINDEXed in vain. Les fichiers postgresql.conf entre les serveurs de données locaux et distants sont exactement les mêmes. Y a-t-il une raison pour laquelle cette base de données essaie de stocker chaque enregistrement avec un espace plus grand sur le disque?
MISE À JOUR 2 - Corrigé
J'ai finalement décidé de reconstruire complètement la base de données à partir de zéro, allant même jusqu'à réinstaller les packages PostgreSQL84 sur le système. Le chemin d'accès à la base de données a été réinitialisé et les espaces disque logiques ont été nettoyés. Le processus de synchronisation des logiciels tiers a repeuplé les tables, et la taille finale s'est révélée être ~ 12 Go ! Malheureusement, cela ne permet en aucune façon de résoudre la source exacte du problème. Je vais le regarder pendant un jour ou deux et voir s'il y a des différences majeures avec la façon dont la base de données revitalisée gère la table TOAST et publier ces résultats ici.
Taille de la relation
ptrdb04=> SELECT nspname || '.' || relname AS "relation",
ptrdb04-> pg_size_pretty(pg_relation_size(C.oid)) AS "size"
ptrdb04-> FROM pg_class C
ptrdb04-> LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
ptrdb04-> WHERE nspname NOT IN ('pg_catalog', 'information_schema')
ptrdb04-> ORDER BY pg_relation_size(C.oid) DESC
ptrdb04-> LIMIT 2;
relation | taille
------------------------- + ---------
pg_toast . pg_toast_17269 | 18 Go
fews00 . warmstates | 1224 Mo
( 2 rangées )
VACUUM VERBOSE ANALYZE timeseries;
INFO: "séries temporelles": trouvé 12699 versions de lignes amovibles, 681961 non amovibles dans 58130 sur 68382 pages DÉTAIL: aucune version de ligne morte ne peut encore être supprimée. Il y avait 105847 pointeurs d'articles inutilisés. 0 pages sont entièrement vides. CPU 0,83 s / 2,08 u sec écoulé 33,36 s. INFO: passer l'aspirateur "pg_toast.pg_toast_17269" INFO: index analysé "pg_toast_17269_index" pour supprimer les versions de ligne 2055849 DÉTAIL: CPU 0.37s / 2.92u sec écoulé 13.29 sec. INFO: «pg_toast_17269»: versions de ligne 2055849 supprimées dans 518543 pages DÉTAIL: CPU 8.60s / 3.21u sec écoulé 358.42 sec. INFO: l'index "pg_toast_17269_index" contient désormais 7346902 versions de ligne sur 36786 pages DÉTAIL: les versions de la ligne d'index 2055849 ont été supprimées. 10410 pages d'index ont été supprimées, 5124 sont actuellement réutilisables. CPU 0,00 s / 0,00 u s écoulé 0,01 s. INFO: "pg_toast_17269": trouvé 1286128 amovibles, 2993389 versions de lignes non amovibles en 1257871 sur 2328079 pages DÉTAIL: aucune version de ligne morte ne peut encore être supprimée. Il y avait 18847 pointeurs d'objets inutilisés. 0 pages sont entièrement vides. CPU 26.56s / 13.04u sec écoulé 714.97 sec. INFO: analyse de "fews00.timeseries" INFO: "timeseries": numérisé 30000 de 68382 pages, contenant 360192 lignes en direct et 0 lignes mortes; 30000 lignes dans l'échantillon, 821022 lignes totales estimées
La seule différence notable après la reconstruction (autre que l'utilisation du disque) est
INFO: "pg_toast_17269": trouvé 1286128 amovible, 2993389 versions de ligne non amoviblecomme @CraigRinger l'a mentionné dans un commentaire. Le nombre de lignes non amovibles est beaucoup plus petit qu'auparavant.
Nouvelle question: d' autres tables peuvent-elles affecter la taille d'une autre table? (via des clés étrangères et autres) La reconstruction de la table n'a rien fait, mais la reconstruction de la base de données entière s'est avérée résoudre le problème.
Réponses:
Cette:
suggère que le problème sous-jacent est que quelque chose peut toujours "voir" ces lignes afin qu'elles ne puissent pas être supprimées.
Les candidats pour cela sont:
Perte des transactions préparées. Vérifiez
pg_catalog.pg_prepared_xacts
; il doit être vide. Exécutez égalementSHOW max_prepared_transactions
; il doit signaler zéro.Sessions de longue durée avec une transaction ouverte et inactive. Dans PostgreSQL 8.4 et supérieur, cela ne devrait être un problème que pour les
SERIALIZABLE
transactions. Vérifiezpg_catalog.pg_stat_activity
pour les<IDLE> in transaction
sessions.Vous avez probablement un client qui ne parvient pas à valider ou à annuler des transactions pendant de longues périodes d'inactivité.
Si cela ne s'avère pas être le cas, la prochaine chose que je vérifierais serait de faire une somme
octet_size
de chaque colonne du tableau d'intérêt. Comparez cela à lapg_relation_size
table et à saTOAST
table d'appoint. S'il y a une grande différence, l'espace consommé n'est probablement plus par des lignes visibles et vous avez probablement des problèmes de ballonnement de table. S'ils sont assez similaires, vous pouvez commencer à réduire l'emplacement de l'utilisation de l'espace en résumant les tailles d'octets par colonne, en obtenant les premières valeurs 'n', etc.la source
SELECT * FROM pg_stat_activity WHERE current_query LIKE '<IDLE>%';
qui rapportent environ 30 à 40 résultats; cependant, cela semble assez normal. J'ai vérifié quelques serveurs "sains", et ils étaient les mêmes.<IDLE> in transaction
et seulement si elles (a) sont inactives depuis un certain temps et (b) utilisent l'SERIALIZABLE
isolement ou si vous êtes sur 8.3 ou plus âgée.TOAST
tableau semble cependant gonflé. BTW, si vous avez utiliséVACUUM FULL
beaucoup de choses sur un serveur antérieur à 9.0, vous voudrez,REINDEX
carVACUUM FULL
sur ces versions, cela pourrait causer un ballonnement d'index important. Je me demande maintenant si quelqu'un a placé un absurdeFILLFACTOR
sur la table des toasts, bien que cela ne devrait pas vous laisser dépasser la consommation d'espace 10 fois.Je n'ai aucune idée de pourquoi il est gonflé. Mais j'ai fait quelques recherches et ce lien a peut-être un aperçu: http://postgresql.1045698.n5.nabble.com/A-154-GB-table-swelled-to-527-GB-on-the-Slony-slave -Comment compact-it-td5543034.html ... Ce n'est pas votre situation exacte mais peut-être est-ce assez proche pour vous aider à atteindre le fond de la météorisation fantôme.
Cependant, je pense que la seule façon de compacter cette table à ce stade est de la CLUSTER. Comme vous manquez d'espace disque, c'est un problème.
Voici ma suggestion pour cela: créer un espace disque logique sur un lecteur différent avec beaucoup d'espace supplémentaire, puis affecter votre table problème à cet espace disque logique. PostgreSQL copiera la table dans le nouvel espace de table (probablement en la verrouillant dans le processus, vous aurez donc besoin d'une fenêtre de maintenance). VACFULL ensuite la table (efface la plupart de l'ancien espace consommé par la table dans l'espace de table par défaut). Ensuite, CLUSTER la table et elle devrait se compacter. Ensuite, remettez-le dans l'espace disque logique par défaut et exécutez à nouveau VACFULL (pour effacer l'espace inutilisé dans le nouvel espace disque logique).
la source