Je suis Charlie

Autres trucs

Accueil

Seulement les RFC

Seulement les fiches de lecture

Ève

Changer une base PostgreSQL de « tablespace »

Première rédaction de cet article le 22 janvier 2012


Un des principaux mécanismes de gestion de l'espace disque dans PostgreSQL est le tablespace. Un tablespace est un répertoire où on place des données du SGBD. Mais, si on change d'avis, comment changer une base de tablespace ?

La tablespace par défaut d'une base se déclare à la création :

% createdb --tablespace grosdisque experience

Ici, la base "experience" est créée sur le tablespace "grosdisque" (créé précédemment par CREATE TABLESPACE). On peut afficher les tablespaces par défaut des bases avec le catalogue système de PostgreSQL :

=> SELECT datname AS database, spcname AS tablespace, spclocation AS directory 
          FROM pg_database INNER JOIN pg_tablespace 
          ON pg_tablespace.oid = pg_database.dattablespace;
     database      |     tablespace     |   directory   
-------------------+--------------------+---------------
 template1         | pg_default         | 
 essais            | pg_default         | 
 experience        | grosdisque         | /some/where/big
...

Et si on s'est trompé, si on a oublié de mettre la base sur le bon tablespace, si la base a grossi au delà de ce qui était prévu ? Depuis la version 8.4 de PostgreSQL, il existe un moyen simple, la commande ALTER DATABASE :


essais=> ALTER DATABASE experience SET TABLESPACE autreendroit;
ERROR:  database "experience" is being accessed by other users
DETAIL:  There are 1 other session(s) using the database.

(Ah oui, il faut qu'aucune session n'accède à la table, ce qui peut
être contraignant.)

essais=> ALTER DATABASE experience SET TABLESPACE autreendroit;
ALTER DATABASE

Et si on gère une base dans une version antérieure de PostgreSQL, et qu'on ne peut pas migrer ? Rien n'est perdu. Il y a bien sûr la solution « bourrin » d'une commande pg_dump, d'une re-création de la base sur le nouveau tablespace, puis d'un pg_restore. C'est très lent, et cela empêche d'accéder à la base en écriture pendant ce temps.

Une solution plus astucieuse est documentée par Lode : elle utilise le fait que le tablespace n'est pas forcément par base mais peut être configuré par table et qu'il est possible, même avant la version 8.4 de PostgreSQL, de changer une table de tablespace. Le principe est donc :


essais=> ALTER DATABASE experience SET default_tablespace = autreendroit;

(Cette première commande changera le tablespace pour les *futures*
tables.)

essais=> ALTER TABLE premiere_table SET TABLESPACE autreendroit;
essais=> ALTER TABLE deuxieme_table SET TABLESPACE autreendroit;
...

Oui, il faut le faire pour toutes les tables, et pour les index également. Ce n'est pas très pratique. Lode automatisait avec PHP, je préfère le faire avec le shell :

% psql --tuples-only -c 'SELECT tablename FROM pg_tables' experience > tmp/tables
% for table in $(cat tmp/tables); do
   echo $table
   psql -c "ALTER TABLE $table SET TABLESPACE autreendroit;" experience
done

Et même chose avec les index :

% psql --tuples-only -c 'SELECT indexname FROM pg_indexes' experience >  tmp/indexes
% for idx in $(cat tmp/indexes); do
   echo $idx
   psql -c "ALTER INDEX $idx SET TABLESPACE autreendroit;" experience
done

C'est bien plus rapide que sauvegarder/restaurer. Rappelez-vous bien que cela ne change pas le tablespace de la base. Il apparaîtra toujours comme l'ancien. Mais toutes les données seront bien dans le nouveau tablespace.

Après, à vous de voir si cela ne serait pas plus simple de migrer vers un PostgreSQL >= 8.4. Mais les grosses bases de données sont souvent des choses fragiles, avec lesquelles on ne peut pas jouer comme on veut. J'ai récemment utilisé la vieille méthode pour une base qu'il aurait été risqué de migrer.

Version PDF de cette page (mais vous pouvez aussi imprimer depuis votre navigateur, il y a une feuille de style prévue pour cela)

Source XML de cette page (cette page est distribuée sous les termes de la licence GFDL)