Il y a quelques malentendus ici:
Le bitmap nul ne fait pas partie de l'en-tête de tuple de tas. Par documentation:
Il y a un en-tête de taille fixe (occupant 23 octets sur la plupart des machines), suivi d'un bitmap nul facultatif ...
Vos 32 colonnes annulables ne sont pas suspectes pour deux raisons:
Le bitmap nul est ajouté par ligne , et uniquement s'il existe au moins une NULL
valeur réelle dans la ligne. Les colonnes nulles n'ont pas d'impact direct, seules les NULL
valeurs réelles le font. Si le bitmap nul est alloué, il est toujours alloué complètement (tout ou rien). La taille réelle du bitmap nul est de 1 bit par colonne, arrondie à l'octet suivant . Par code souce actuel:
#define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8)
Le bitmap nul est alloué après l'en-tête de tuple de tas et suivi d'un OID facultatif, puis de données de ligne. Le début d'un OID ou d'une ligne de données est indiqué par t_hoff
dans l'en-tête. Par code source de commentaire :
Notez que t_hoff doit être un multiple de MAXALIGN.
Il y a un octet libre après l'en-tête de tuple de tas, qui occupe 23 octets. Ainsi, le bitmap nul pour les lignes jusqu'à 8 colonnes est effectivement sans frais supplémentaires. Avec la 9e colonne du tableau, t_hoff
un autre MAXALIGN
octet (généralement 8) est avancé pour fournir 64 autres colonnes. La prochaine frontière serait donc à 72 colonnes.
Pour afficher les informations de contrôle d'un cluster de base de données PostgreSQL (incl. MAXALIGN
), Exemple pour une installation typique de Postgres 9.3 sur une machine Debian:
sudo /usr/lib/postgresql/9.3/bin/pg_controldata /var/lib/postgresql/9.3/main
J'ai mis à jour les instructions dans la réponse connexe que vous avez citée .
Tout cela mis à part, même si votre ALTER TABLE
instruction déclenche une réécriture de table entière (ce qu'elle fait probablement, en changeant un type de données), 250 Ko ne sont vraiment pas beaucoup et seraient une question de secondes sur n'importe quelle machine à mi-chemin décente (à moins que les lignes soient anormalement grandes) . 10 minutes ou plus indiquent un problème complètement différent. Votre déclaration attend très probablement un verrou sur la table.
Le nombre croissant d'entrées dans pg_stat_activity
signifie des transactions plus ouvertes - indique un accès simultané sur la table (le plus probable) qui doit attendre la fin de l'opération.
Quelques clichés dans le noir
Vérifiez l'éventuel ballonnement de la table, essayez une solution douce VACUUM mytable
ou plus agressive VACUUM FULL mytable
- qui pourrait rencontrer les mêmes problèmes de concurrence, car ce formulaire acquiert également un verrou exclusif. Vous pouvez essayer pg_repack à la place ...
Je commencerais par inspecter les problèmes possibles avec les index, les déclencheurs, la clé étrangère ou d'autres contraintes, en particulier ceux impliquant la colonne. En particulier, un index corrompu pourrait être impliqué? Essayez-les REINDEX TABLE mytable;
ou DROP
tous et ré-ajoutez-les après ALTER TABLE
dans la même transaction .
Essayez d'exécuter la commande dans la nuit ou chaque fois qu'il n'y a pas beaucoup de charge.
Une méthode de force brute serait d'arrêter l'accès au serveur, puis de réessayer:
Sans pouvoir le cerner, la mise à niveau vers la version actuelle ou la prochaine 9.4 en particulier pourrait aider. Plusieurs améliorations ont été apportées aux grandes tables et aux détails de verrouillage. Mais s'il y a quelque chose de cassé dans votre base de données, vous devriez probablement le découvrir en premier.
SET NOT NULL
ne modifie pas le type, il ajoute simplement une contrainte - mais la contrainte doit être vérifiée par rapport à la table, et cela nécessite une analyse complète de la table. 9.4 améliore certains de ces cas en prenant des verrous plus faibles, mais il est toujours assez lourd.