web-dev-qa-db-fra.com

Comment faire une base de données RDS PostgreSQL?

Comme vous l'avez peut-être remarqué, en tant que base de données entièrement gérée en tant que produit de service, le service de base de données relationnelle AWS (RDS) restreint l'exécution des commandes userland.

J'avais la mise en place d'une base de données de production et j'ai obtenu mon pg_largeobject Table gonflée à 40% de la capacité du dispositif virtuel entière de persistance.

Comment puis-je courir vacuumlo (joliment bien expliqué dans une autre question dba.se ICI ) sur une base de données PostgreSQL de RDS.

3
48347

Trouver - ICI (dans le miroir GITHUB des Sources de vacuumlo pour la version de base de données PostgreSQL J'utilisais à ce moment-là.

Vous pouvez imaginer le reste: je viens de imiter ce que le programme effectue, également simplement décrit ici .

1. Construction de la table temporaire.

Préparez la table temporaire des références d'objet ou des OID.

1.1. Table LOB temporaire sous forme de copie de la table LOB complète.

=> SET search_path = pg_catalog;
[...]
=> CREATE TABLE vacuum_lo_removeme AS \
        SELECT oid AS lo FROM pg_largeobject_metadata;
[...]
=> ANALYZE vacuum_lo_removeme;
[...]
=> _

1.2. Limiter la table de lobe temporaire.

Effectuez la requête qui vous renvoie toutes vos colonnes de base de données saisies OID:

=> SELECT
     s.nspname, c.relname, a.attname FROM pg_class c, pg_attribute a
     , pg_namespace s, pg_type t
   WHERE
     a.attnum > 0 AND NOT a.attisdropped AND a.attrelid = c.oid
     AND a.atttypid = t.oid AND c.relnamespace = s.oid 
     AND t.typname in ('oid', 'lo') AND c.relkind in ('r','m')
     AND s.nspname !~ '^pg_';

Ensuite, vous devez exécuter cette requête pour tous les résultats obtenus par la requête antérieure (note ${VARIABLE} est quelque chose que vous devez vous substituer en fonction de votre kilométrage) afin de supprimer de la table temporaire toutes les OID d'objets réellement utilisés. :

=> DELETE FROM vacuum_lo_removeme WHERE \
        lo IN (SELECT ${column} FROM ${SCHEMA}.${TABLE});

Dans mon cas, il ne s'agissait que de deux tables totalement sur cinq colonnes et réellement des tables vides, si naturellement les cinq DELETE requêtes ne faisaient rien. Si vous avez un plus grand OID activé Subschema Vous pourriez avoir besoin d'automatiser cela en quelque sorte.

2. Grands objets Dislining.

Enfin, le programme déclare un curseur qui présente les cellules restantes lo de la table temporaire, les purgeant avec un appel de fonction lo_unlink.

2.a. Ne le faites pas de cette façon.

J'aurais dû automatiser cela avec une procédure stockée PLPGSQL, mais depuis que je suis suce sur ce type de tâches, je viens de publier cette doublure:

$ echo 'SELECT COUNT(*) FROM vacuum_lo_removeme;' | \
        $MY_AUTOMATABLE_PSQL_MILEAGE 
  count  
---------
 1117233
(1 row)

Ensuite, cet autre qui itière en sélectionnant le premier orphelin OID dans la table temporaire des OID orphelin, puis le désabonnement et le retirer de la table:

$ for i in {1..1117000}; do \
        export oid=$(echo 'SELECT * FROM vacuum_lo_removeme LIMIT 1' | \
        $MY_AUTOMATABLE_PSQL_MILEAGE | grep -v 'lo\|\-\-\-\-\|row\|^$' | \
        sed s/\ //g) && \
        echo "SELECT lo_unlink($oid); \
              DELETE FROM vacuum_lo_removeme WHERE lo = $oid" | \
              $MY_AUTOMATABLE_PSQL_MILEAGE; \
        done
 lo_unlink 
-----------
         1
(1 row)

DELETE 1
 lo_unlink 
-----------
         1
(1 row)

DELETE 1
 lo_unlink 
-----------
         1
(1 row)

DELETE 1
 lo_unlink 
-----------
         1
(1 row)

DELETE 1
ERROR:  must be owner of large object 18448
DELETE 1
ERROR:  must be owner of large object 18449
DELETE 1
ERROR:  must be owner of large object 18450
DELETE 1
ERROR:  must be owner of large object 18451
[...]
 lo_unlink 
-----------
         1
(1 row)

DELETE 1
[...]

Je savais que c'était sous-optimisé comme l'enfer, mais je l'ai laissé éliminer lentement ces archives orphelines. Lorsqu'on n'étant pas dba à tous ceux-ci, ces doublures peuvent être plus faciles à forger que de travailler de manière significative Idiomatic PLPGSQL.

Mais c'était trop lent pour laisser ça comme ça.

2.b. Faites cela mieux que 2.A (mais pas encore une balle d'argent).

Vous serez en mesure d'accélérer un gros objet de dissimulation avec quelque chose de simple comme:

=> CREATE OR REPLACE FUNCTION unlink_Orphan_los() RETURNS VOID AS $$
DECLARE
  iterator integer := 0;
  largeoid OID;
  myportal CURSOR FOR SELECT lo FROM vacuum_lo_removeme;
BEGIN
  OPEN myportal;
  LOOP
    FETCH myportal INTO largeoid;
    EXIT WHEN NOT FOUND;
    PERFORM lo_unlink(largeoid);
    DELETE FROM vacuum_lo_removeme WHERE lo = largeoid;
    iterator := iterator + 1;
    RAISE NOTICE '(%) removed lo %?', iterator, largeoid;
    IF iterator = 100 THEN EXIT; END IF;
  END LOOP;
END;$$LANGUAGE plpgsql;

[~ # ~] NOTE [~ # ~ ~] Il n'est pas nécessaire de dissuader les objets de grande taille 100 à la fois, pas même un numéro particulier x d'entre eux À une époque, mais le dissociant 100 à la fois est la base la plus sûre applicable à la configuration de la mémoire par défaut de toutes les tailles d'instance AWS. Si vous utilisez un nombre excessivement grand pour cela, vous risquez une défaillance de la fonction en raison de la mémoire insuffisamment assignée; La façon dont vous pouvez faire dépendra de la quantité d'objets à dissuader et de leur taille, de type et de taille, ainsi que du degré de configuration supplémentaire manuelle appliquée.

Qui est un peu facile à forger pour une personne non DBA, puis l'appelant avec quelque chose comme

$ for i in {0..$WHATEVER}; do echo 'SELECT unlink_Orphan_los()' | \
        $YOUR_AUTOMATABLE_PSQL_MILEAGE

${WHATEVER} est une constante construite en fonction de la taille de la table de gros objets temporaires et du nombre de serrures par transaction Votre configuration permet de permettre (j'utilise des paramètres par défaut de RDS, mais itération de bash je suppose que je Vous n'êtes même pas obligé d'apprendre à savoir quel est le plus grand nombre de lo_unlink s le RDBMS permet de connaître le courant max_locks_per_transaction.

3. VACUUM gros tables d'objet.

Apparuré par ce fil dans la liste de diffusion Postgres J'ai compris que je devrais VACUUM _ pg_largeobject après le déshabillage des objets.

Je ne suis pas sûr que d'entre eux sont l'ensemble minimum requis ou le temps nécessaire à leur exécution, mais certains d'entre eux pourraient être utiles, et aucun ne devrait causer de dommages: j'ai couru VACUUM ANALYZE VERBOSE pg_largeobject_metadata; VACUUM ANALYZE VERBOSE pg_largeobject; VACUUM FULL ANALYZE VERBOSE pg_largeobject_metadata; VACUUM FULL ANALYZE VERBOSE pg_largeobject; plusieurs fois pendant que le micro-instance dissociant les objets (prenait un très grand temps, hélas), d'abord lorsque environ 1/4 d'objets déjà gagné, et un peu de stockage a été remis au système d'exploitation, deuxièmement, lorsque environ 1/3 d'objets déjà gagnés, et certains Un autre petit stockage a été renvoyé au système d'exploitation, troisièmement, lorsque environ 3/5 objets ont déjà été non liés, l'instance a subi un budget de stockage massif au système d'exploitation:

enter image description here

enter image description here

Ce renvoi de stockage massif était ce que je cherchais. Après avoir exécuté la requête pour les plus grandes tables trouvées à la page d'accueil officielle , avec moins de 3/4 d'objets total non liés, la table d'objets a été réduite à moins de 3Gib, loin de la valeur initiale et encore plus gonflée 20Gib .

[~ # ~] NOTE [~ # ~ # ~] Automatiser rapideVACUUM ANALYZE itération sur des tables a les mêmes effets à long terme (de nettoyer la table à partir d'utiliser un stockage en excès de disque) comme exécutant un seul VACUUM FULL, mais sans acquérir une serrure exclusive.

3
48347

Tous les crédits à https://dba.stackexchange.com/a/174664/83878 Mais je pourrais simplifier la solution dans mon cas. Il n'y a qu'un seul schéma dans mon cas. Aussi la première déclaration search_path = pg_catalog ne fonctionne pas dans mon cas car je n'ai aucune autorisation pour modifier le catalogue du système. Je pourrais également simplifier considérablement la procédure de démontrage avec une seule instruction.

  1. Créer une table TMP vacuum_lo_removeme:

Créer une table si ce n'est pas vide Vacuum_lo_Removeme comme sélectionnez OID comme LO de pg_catalog.pg_largeObject_metadata

Remarque: Ceci est créé dans le schéma par défaut maintenant.

  1. Recherchez tous les noms de table et de colonne où un OID est utilisé:
SELECT c.relname as tablename, a.attname as columnname FROM pg_class c, pg_attribute a, pg_namespace s, pg_type t WHERE a.attnum > 0 AND NOT a.attisdropped AND a.attrelid = c.oid AND a.atttypid = t.oid AND c.relnamespace = s.oid AND t.typname in ('oid', 'lo') AND c.relkind in ('r','m') AND s.nspname !~ '^pg_' AND relname != 'vacuum_lo_removeme'
  1. Itérate sur toutes les tables et retirer les objets importants encore utilisés de la table TMP:
DELETE FROM vacuum_lo_removeme WHERE lo IN (SELECT ${columnname} FROM ${tablename}

Exemple: J'utilise Java ici (rs est le résultat de l'instruction précédente):

            while (rs.next()) {
                String tablename = rs.getString("tablename");
                String columnname = rs.getString("columnname");
                // remove OID which must be kept
                String removeUsedOids = String.format("DELETE FROM vacuum_lo_removeme WHERE lo IN (SELECT \"%s\" FROM \"%s\")",
                        columnname, tablename);
                stmt = connection.createStatement();
                stmt.executeUpdate(removeUsedOids);
            }
  1. Enlever les los orphelins
SELECT count(lo_unlink(lo)) from vacuum_lo_removeme where lo in (select loid from pg_catalog.pg_largeobject)
  1. DROP TEMP DB
DROP table vacuum_lo_removeme
0
k_o_