496 votes

Comment trouver le nombre de lignes pour toutes vos tables dans Postgres ?

Je cherche un moyen de trouver le nombre de lignes pour toutes mes tables dans Postgres. Je sais que je peux le faire une table à la fois avec :

SELECT count(*) FROM table_name;

mais j'aimerais voir le nombre de lignes de toutes les tables, puis les ordonner pour avoir une idée de la taille de mes tables.

736voto

Greg Smith Points 5443

Il y a trois façons d'obtenir ce genre de compte, chacune ayant ses propres inconvénients.

Si vous voulez un compte réel, vous devez exécuter l'instruction SELECT comme celle que vous avez utilisée pour chaque table. Ceci est dû au fait que PostgreSQL conserve les informations de visibilité de la ligne dans la ligne elle-même, pas ailleurs, donc tout comptage précis ne peut être que relatif à une transaction. Vous obtenez un compte de ce que cette transaction voit au moment où elle s'exécute. Vous pourriez automatiser cette opération pour l'exécuter sur chaque table de la base de données, mais vous n'avez probablement pas besoin de ce niveau de précision ou ne voulez pas attendre aussi longtemps.

La deuxième approche consiste à noter que le collecteur de statistiques suit à peu près le nombre de lignes qui sont "vivantes" (non supprimées ou rendues obsolètes par des mises à jour ultérieures) à tout moment. Cette valeur peut être légèrement erronée en cas d'activité intense, mais elle constitue généralement une bonne estimation :

SELECT schemaname,relname,n_live_tup 
  FROM pg_stat_user_tables 
  ORDER BY n_live_tup DESC;

Cela peut également vous montrer combien de lignes sont mortes, ce qui est en soi un chiffre intéressant à surveiller.

La troisième façon est de noter que la commande système ANALYZE, qui est exécutée par le processus autovacuum régulièrement à partir de PostgreSQL 8.3 pour mettre à jour les statistiques de la table, calcule également une estimation de rangée. Vous pouvez l'attraper comme ceci :

SELECT 
  nspname AS schemaname,relname,reltuples
FROM pg_class C
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE 
  nspname NOT IN ('pg_catalog', 'information_schema') AND
  relkind='r' 
ORDER BY reltuples DESC;

Il est difficile de dire laquelle de ces requêtes est la meilleure à utiliser. Normalement, je prends cette décision en fonction des informations plus utiles que je souhaite utiliser dans pg_class ou dans pg_stat_user_tables. Pour des comptages de base, juste pour voir la taille des choses en général, l'un ou l'autre devrait être assez précis.

14 votes

Pour des raisons de complétude, veuillez ajouter ceci pour la première option (merci à @a_horse_with_no_name) : with tbl as (SELECT table_schema,table_name FROM information_schema.tables where table_name not like 'pg_%' and table_schema in ('public')) select table_schema, table_name, (xpath('/row/c/text()', query_to_xml(format('select count(*) as c from %I.%I', table_schema, table_name), false, true, '')))[1]::text::int as rows_n from tbl ORDER BY 3 DESC;

1 votes

@Greg Smith Quelle version a été introduite n_live_tup ? Ma base de données Redshift ne possède pas cette colonne. C'est un dérivé de Postgres 8.0.2.

2 votes

La requête de la "deuxième approche" (utilisant pg_stat_user_tables ) a retourné la plupart des zéros dans n_live_tup pour moi parce que ANALYZE n'avait jamais été exécutée. Plutôt que d'exécuter ANALYZE sur chaque schéma/table et attendre indéfiniment une réponse, j'ai d'abord vérifié les résultats en utilisant la "troisième approche" et celle-là (utilisant pg_class ) ont donné des résultats très précis.

25voto

ig0774 Points 10389

Si les données potentiellement périmées ne vous dérangent pas, vous pouvez accéder aux mêmes statistiques que celles utilisées par l'optimiseur de requêtes .

Quelque chose comme :

SELECT relname, n_tup_ins - n_tup_del as rowcount FROM pg_stat_all_tables;

1 votes

@mlissner : Si votre intervalle d'autovacuation est trop long ou si vous n'avez pas fait d'aspiration manuelle ANALYZE sur la table, les statistiques peuvent être très différentes. C'est une question de charge de la base de données et de la façon dont elle est configurée (si les statistiques sont mises à jour plus fréquemment, elles seront plus précises, mais cela pourrait réduire les performances d'exécution). En fin de compte, la seule façon d'obtenir des données précises est d'exécuter le programme select count(*) from table pour toutes les tables.

11voto

Stew-au Points 78

Je ne sais pas si une réponse dans bash est acceptable pour vous, mais pour info...

PGCOMMAND=" psql -h localhost -U fred -d mydb -At -c \"
            SELECT   table_name
            FROM     information_schema.tables
            WHERE    table_type='BASE TABLE'
            AND      table_schema='public'
            \""
TABLENAMES=$(export PGPASSWORD=test; eval "$PGCOMMAND")

for TABLENAME in $TABLENAMES; do
    PGCOMMAND=" psql -h localhost -U fred -d mydb -At -c \"
                SELECT   '$TABLENAME',
                         count(*) 
                FROM     $TABLENAME
                \""
    eval "$PGCOMMAND"
done

7 votes

En gros, cela revient au même. select count(*) from table_name; dans l'OP !

8voto

Yuri Levinsky Points 411

En général, je ne me fie pas aux statistiques, surtout dans PostgreSQL.

SELECT table_name, dsql2('select count(*) from '||table_name) as rownum
FROM information_schema.tables
WHERE table_type='BASE TABLE'
    AND table_schema='livescreen'
ORDER BY 2 DESC;

CREATE OR REPLACE FUNCTION dsql2(i_text text)
  RETURNS int AS
$BODY$
Declare
  v_val int;
BEGIN
  execute i_text into v_val;
  return v_val;
END; 
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

0 votes

C'est bien, mais la première requête devrait également inclure le schéma de la valeur rownum. S'il y a des noms contradictoires dans différents schémas, cela ne fonctionnera pas comme prévu. Cette partie de la requête devrait donc ressembler à ceci dsql2('select count(*) from livescreen.'||table_name) ou mieux, il pourrait être transformé en une fonction à part entière.

6voto

Gnanam Points 2169

Je ne me souviens pas de l'URL d'où j'ai récupéré cela. Mais j'espère que cela pourra vous aider :

CREATE TYPE table_count AS (table_name TEXT, num_rows INTEGER); 

CREATE OR REPLACE FUNCTION count_em_all () RETURNS SETOF table_count  AS '
DECLARE 
    the_count RECORD; 
    t_name RECORD; 
    r table_count%ROWTYPE; 

BEGIN
    FOR t_name IN 
        SELECT 
            c.relname
        FROM
            pg_catalog.pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
        WHERE 
            c.relkind = ''r''
            AND n.nspname = ''public'' 
        ORDER BY 1 
        LOOP
            FOR the_count IN EXECUTE ''SELECT COUNT(*) AS "count" FROM '' || t_name.relname 
            LOOP 
            END LOOP; 

            r.table_name := t_name.relname; 
            r.num_rows := the_count.count; 
            RETURN NEXT r; 
        END LOOP; 
        RETURN; 
END;
' LANGUAGE plpgsql; 

Exécuter select count_em_all(); devrait vous donner le nombre de lignes de toutes vos tables.

1 votes

C'est une bonne idée de citer les noms de colonnes (comme quote_ident(t_name.relname) ) pour assurer une prise en charge correcte des noms inhabituels ("nom de colonne", par exemple).

0 votes

Pour l'abandonner ensuite : DROP FUNCTION count_em_all() ;

0 votes

J'ai obtenu une erreur : select count_em_all() ; ERROR : syntax error at or near "group" LINE 1 : SELECT COUNT() AS "count" FROM group ^ QUERY : SELECT COUNT() AS "count" FROM group CONTEXT : PL/pgSQL function count_em_all() line 18 at FOR over EXECUTE statement

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X