web-dev-qa-db-fra.com

Postgresql - change la taille d'une colonne varchar

J'ai une question à propos de la commande ALTER TABLE sur une très grande table (près de 30 millions de lignes). Une de ses colonnes est une varchar(255) et j'aimerais la redimensionner en varchar(40). En gros, je voudrais changer ma colonne en lançant la commande suivante:

ALTER TABLE mytable ALTER COLUMN mycolumn TYPE varchar(40);

Je n'ai aucun problème si le processus est très long, mais il semble que ma table n'est plus lisible lors de la commande ALTER TABLE. Y a-t-il un moyen plus intelligent? Peut-être ajouter une nouvelle colonne, copier les valeurs de l'ancienne colonne, supprimer l'ancienne et enfin renommer la nouvelle?

Tout indice sera grandement apprécié! Merci d'avance,

Note: J'utilise PostgreSQL 9.0.

130
Labynocle

Il y a une description de la façon de faire ceci en Redimensionner une colonne dans une table PostgreSQL sans changer les données . Vous devez pirater les données du catalogue de base de données. La seule façon de faire cela officiellement est avec ALTER TABLE, et comme vous l'avez noté, les modifications verrouillent et réécrivent la totalité de la table pendant son exécution.

Assurez-vous de lire la section Types de caractères de la documentation avant de la modifier. Toutes sortes de cas étranges dont il faut être conscient ici. La vérification de la longueur est effectuée lorsque les valeurs sont stockées dans les lignes. Si vous piratez une limite inférieure, cela ne réduira pas du tout la taille des valeurs existantes. Il serait sage d'effectuer une analyse sur l'ensemble de la table à la recherche de lignes où la longueur du champ est supérieure à 40 caractères après la modification. Vous aurez besoin de comprendre comment les tronquer manuellement - pour que vous puissiez récupérer des verrous uniquement surdimensionnés - car si quelqu'un essaye de mettre à jour quelque chose sur cette ligne, il le rejettera car il est trop gros maintenant. il va stocker la nouvelle version de la ligne. L'hilarité s'ensuit pour l'utilisateur.

VARCHAR est un type terrible qui n'existe dans PostgreSQL que pour se conformer à sa partie terrible du standard SQL associée. Si vous ne vous souciez pas de la compatibilité de plusieurs bases de données, envisagez de stocker vos données au format TEXT et ajoutez une contrainte pour en limiter la longueur. Les contraintes que vous pouvez modifier sans ce problème de verrouillage/réécriture de la table et peuvent effectuer davantage de vérifications d'intégrité que la simple vérification de longueur faible.

65
Greg Smith

Dans PostgreSQL 9.1, il existe un moyen plus simple

http://www.postgresql.org/message-id/[email protected]

CREATE TABLE foog(a varchar(10));

ALTER TABLE foog ALTER COLUMN a TYPE varchar(30);

postgres=# \d foog

 Table "public.foog"
 Column |         Type          | Modifiers
--------+-----------------------+-----------
 a      | character varying(30) |
77
sir_leslie

Ok, je suis probablement en retard à la fête, MAIS ...

IL N'EST PAS BESOIN DE REDIMENSIONNER LA COLONNE DANS VOTRE CAS!

Contrairement à certaines autres bases de données, Postgres est assez intelligent pour utiliser seulement assez d'espace pour adapter la chaîne (même en utilisant la compression pour des chaînes plus longues). Ainsi, même si votre colonne est déclarée en tant que VARCHAR (255), si vous stockez des chaînes de 40 caractères dans la colonne, l’utilisation de l’espace sera de 40 octets + 1 octet d’overhead.

La mémoire requise pour une chaîne courte (jusqu'à 126 octets) est de 1 octet plus la chaîne réelle, qui inclut le remplissage d'espace dans le cas d'un caractère. Les chaînes plus longues ont 4 octets de surcharge au lieu de 1. Les chaînes longues sont automatiquement compressées par le système, de sorte que les exigences physiques sur le disque risquent d'être moindres. Des valeurs très longues sont également stockées dans des tables d'arrière-plan afin qu'elles n'interfèrent pas avec un accès rapide à des valeurs de colonne plus courtes.

( http://www.postgresql.org/docs/9.0/interactive/datatype-character.html )

La spécification de taille dans VARCHAR sert uniquement à vérifier la taille des valeurs insérées, elle n’affecte pas la structure du disque. En fait, les champs VARCHAR et TEXT sont stockés de la même manière dans Postgres .

44
Sergey

J'étais confronté au même problème en essayant de tronquer un VARCHAR de 32 à 8 et d'obtenir le ERROR: value too long for type character varying(8). Je souhaite rester aussi proche que possible de SQL, car j'utilise une structure de type JPA créée par nous-mêmes et que nous pourrions être amenés à basculer vers un autre SGBD en fonction des choix du client (PostgreSQL étant la valeur par défaut). Par conséquent, je ne veux pas utiliser le truc de la modification des tables système.

J'ai fini par utiliser l'instruction USING dans le ALTER TABLE:

ALTER TABLE "MY_TABLE" ALTER COLUMN "MyColumn" TYPE varchar(8)
USING substr("MyColumn", 1, 8)

Comme @raylu l'a noté, ALTER acquiert un verrou exclusif sur la table afin que toutes les autres opérations soient retardées jusqu'à la fin.

32
Matthieu

Ajouter une nouvelle colonne et en remplacer une nouvelle par une ancienne a fonctionné pour moi, sous redshift postgresql, référez-vous à ce lien pour plus de détails https://Gist.github.com/mmasashi/71074

BEGIN;
LOCK users;
ALTER TABLE users ADD COLUMN name_new varchar(512) DEFAULT NULL;
UPDATE users SET name_new = name;
ALTER TABLE users DROP name;
ALTER TABLE users RENAME name_new TO name;
END;
7
spats

Voici le cache de la page décrite par Greg Smith. Au cas où cela mourrait également, l'instruction alter se présente comme suit:

UPDATE pg_attribute SET atttypmod = 35+4
WHERE attrelid = 'TABLE1'::regclass
AND attname = 'COL1';

Si votre table est TABLE1, la colonne est COL1 et que vous souhaitez la définir sur 35 caractères (le +4 est nécessaire pour les besoins de l'héritage en fonction du lien, éventuellement le temps système mentionné par A.H. dans les commentaires).

7
Tom

si vous mettez l'alter dans une transaction, la table ne doit pas être verrouillée:

BEGIN;
  ALTER TABLE "public"."mytable" ALTER COLUMN "mycolumn" TYPE varchar(40);
COMMIT;

cela a fonctionné pour moi extrêmement rapide, quelques secondes sur une table de plus de 400 000 lignes.

7
jacktrade

J'ai trouvé un moyen très simple de changer la taille, c'est-à-dire l'annotation @Size (min = 1, max = 50), qui fait partie de "import javax.validation.constraints", c'est-à-dire "import javax.validation.constraints.Size;"

@Size(min = 1, max = 50)
private String country;


when executing  this is hibernate you get in pgAdmin III 


CREATE TABLE address
(
.....
  country character varying(50),

.....

)
1
Tito