it-swarm.com.de

Wie finden Sie die Zeilenanzahl für alle Ihre Tabellen in Postgres

Ich suche nach einer Möglichkeit, die Zeilenanzahl für alle meine Tabellen in Postgres zu ermitteln. Ich weiß, dass ich diesen einen Tisch nach dem anderen machen kann mit:

SELECT count(*) FROM table_name;

aber ich möchte die Zeilenanzahl für alle Tabellen sehen und dann danach sortieren, um eine Vorstellung davon zu bekommen, wie groß meine Tabellen sind.

346
mmrobins

Es gibt drei Möglichkeiten, diese Art von Zählung zu erhalten, wobei jede ihre eigenen Nachteile hat.

Wenn Sie eine echte Zählung wünschen, müssen Sie die SELECT-Anweisung ausführen, wie Sie sie für jede Tabelle verwendet haben. Dies liegt daran, dass PostgreSQL die Informationen zur Zeilensichtbarkeit in der Zeile selbst und nicht an einem anderen Ort aufbewahrt, sodass eine genaue Zählung nur relativ zu einer Transaktion erfolgen kann. Sie erhalten eine Zählung dessen, was diese Transaktion zu dem Zeitpunkt sieht, zu dem sie ausgeführt wird. Sie könnten dies so automatisieren, dass es für jede Tabelle in der Datenbank ausgeführt wird, aber Sie benötigen wahrscheinlich nicht diese Genauigkeitsstufe oder möchten so lange warten.

Der zweite Ansatz sieht vor, dass der Statistiksammler ungefähr nachverfolgt, wie viele Zeilen zu irgendeinem Zeitpunkt "aktiv" sind (nicht gelöscht oder durch spätere Aktualisierungen veraltet). Dieser Wert kann bei starker Aktivität etwas abweichen, ist aber im Allgemeinen eine gute Schätzung:

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

Das kann Ihnen auch zeigen, wie viele Zeilen tot sind, was selbst eine interessante zu überwachende Zahl ist.

Die dritte Möglichkeit besteht darin, zu beachten, dass der ANALYZE-Befehl des Systems, der vom Autovacuum-Prozess regelmäßig ab PostgreSQL 8.3 ausgeführt wird, um die Tabellenstatistik zu aktualisieren, auch eine Zeilenschätzung berechnet. Sie können das wie folgt greifen:

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;

Welche dieser Abfragen besser zu verwenden ist, ist schwer zu sagen. Normalerweise treffe ich diese Entscheidung basierend darauf, ob es nützlichere Informationen gibt, die ich auch in pg_class oder in pg_stat_user_tables verwenden möchte. Für grundlegende Zählzwecke sollte entweder genau genug sein, um zu sehen, wie groß die Dinge im Allgemeinen sind.

507
Greg Smith

Hier ist eine Lösung, die keine Funktionen benötigt, um eine genaue Zählung für jede Tabelle zu erhalten:

select table_schema, 
       table_name, 
       (xpath('/row/cnt/text()', xml_count))[1]::text::int as row_count
from (
  select table_name, table_schema, 
         query_to_xml(format('select count(*) as cnt from %I.%I', table_schema, table_name), false, true, '') as xml_count
  from information_schema.tables
  where table_schema = 'public' --<< change here for the schema you want
) t

query_to_xml Führt die übergebene SQL-Abfrage aus und gibt eine XML mit dem Ergebnis zurück (die Zeilenanzahl für diese Tabelle). Die äußere xpath() extrahiert dann die Zählerinformationen aus dieser XML und konvertiert sie in eine Zahl

Die abgeleitete Tabelle ist nicht wirklich notwendig, macht aber die xpath() etwas verständlicher - andernfalls müsste die gesamte query_to_xml() an die xpath() -Funktion übergeben werden.

43

Um Schätzungen zu erhalten, siehe Greg Smiths Antwort .

Um genaue Zahlen zu erhalten, sind die anderen Antworten mit einigen, zum Teil gravierenden Problemen behaftet (siehe unten). Hier ist eine Version, die hoffentlich besser ist:

CREATE FUNCTION rowcount_all(schema_name text default 'public')
  RETURNS table(table_name text, cnt bigint) as
$$
declare
 table_name text;
begin
  for table_name in SELECT c.relname FROM pg_class c
    JOIN pg_namespace s ON (c.relnamespace=s.oid)
    WHERE c.relkind = 'r' AND s.nspname=schema_name
  LOOP
    RETURN QUERY EXECUTE format('select cast(%L as text),count(*) from %I.%I',
       table_name, schema_name, table_name);
  END LOOP;
end
$$ language plpgsql;

Als Parameter wird ein Schemaname verwendet, oder public, wenn kein Parameter angegeben ist.

Um mit einer bestimmten Liste von Schemas oder einer Liste aus einer Abfrage zu arbeiten, ohne die Funktion zu ändern, kann diese aus einer Abfrage heraus wie folgt aufgerufen werden:

WITH rc(schema_name,tbl) AS (
  select s.n,rowcount_all(s.n) from (values ('schema1'),('schema2')) as s(n)
)
SELECT schema_name,(tbl).* FROM rc;

Dies erzeugt eine 3-Spalten-Ausgabe mit dem Schema, der Tabelle und der Zeilenzahl.

Hier sind einige Probleme in den anderen Antworten, die diese Funktion vermeidet:

  • Tabellen- und Schemanamen sollten nicht ohne Anführungszeichen in ausführbares SQL eingefügt werden, weder mit quote_ident Noch mit der moderneren Funktion format() mit der Formatzeichenfolge %I. Andernfalls kann eine böswillige Person ihre Tabelle tablename;DROP TABLE other_table Benennen, was als Tabellenname vollkommen gültig ist.

  • Auch ohne die Probleme mit SQL-Injection und lustigen Zeichen kann der Tabellenname in verschiedenen Varianten vorkommen. Wenn eine Tabelle ABCD und eine andere abcd heißt, muss die SELECT count(*) FROM... einen in Anführungszeichen gesetzten Namen verwenden, da sie sonst ABCD überspringt und abcd zweimal. Das %I Von format macht das automatisch.

  • information_schema.tables Listet zusätzlich zu Tabellen benutzerdefinierte zusammengesetzte Typen auf, auch wenn table_type 'BASE TABLE' (!) Ist. Infolgedessen können wir bei information_schema.tables Nicht iterieren, da wir sonst das Risiko eingehen, select count(*) from name_of_composite_type zu haben, was fehlschlagen würde. OTOH pg_class where relkind='r' Sollte immer gut funktionieren.

  • Die Art von COUNT () ist bigint, nicht int. Möglicherweise sind Tabellen mit mehr als 2,15 Milliarden Zeilen vorhanden (eine Zählung (*) ist jedoch eine schlechte Idee).

  • Es muss kein permanenter Typ erstellt werden, damit eine Funktion eine Ergebnismenge mit mehreren Spalten zurückgibt. RETURNS TABLE(definition...) ist eine bessere Alternative.

22
Daniel Vérité

Wenn Ihnen möglicherweise veraltete Daten nichts ausmachen, können Sie auf dieselben vom Abfrageoptimierer verwendeten Statistiken zugreifen .

So etwas wie:

SELECT relname, n_tup_ins - n_tup_del as rowcount FROM pg_stat_all_tables;
16
ig0774

Die knifflige, praktische Antwort für Leute, die versuchen zu bewerten, welchen Heroku-Plan sie benötigen und nicht warten können, bis Herokus langsamer Zeilenzähler aktualisiert wird:

Grundsätzlich möchten Sie \dt In psql ausführen und die Ergebnisse in Ihren bevorzugten Texteditor kopieren (so sieht es aus:

 public | auth_group                     | table | axrsosvelhutvw
 public | auth_group_permissions         | table | axrsosvelhutvw
 public | auth_permission                | table | axrsosvelhutvw
 public | auth_user                      | table | axrsosvelhutvw
 public | auth_user_groups               | table | axrsosvelhutvw
 public | auth_user_user_permissions     | table | axrsosvelhutvw
 public | background_task                | table | axrsosvelhutvw
 public | Django_admin_log               | table | axrsosvelhutvw
 public | Django_content_type            | table | axrsosvelhutvw
 public | Django_migrations              | table | axrsosvelhutvw
 public | Django_session                 | table | axrsosvelhutvw
 public | exercises_assignment           | table | axrsosvelhutvw

), dann führe eine reguläre Suche durch und ersetze sie wie folgt:

^[^|]*\|\s+([^|]*?)\s+\| table \|.*$

zu:

select '\1', count(*) from \1 union/g

was dir etwas sehr ähnliches bringen wird:

select 'auth_group', count(*) from auth_group union
select 'auth_group_permissions', count(*) from auth_group_permissions union
select 'auth_permission', count(*) from auth_permission union
select 'auth_user', count(*) from auth_user union
select 'auth_user_groups', count(*) from auth_user_groups union
select 'auth_user_user_permissions', count(*) from auth_user_user_permissions union
select 'background_task', count(*) from background_task union
select 'Django_admin_log', count(*) from Django_admin_log union
select 'Django_content_type', count(*) from Django_content_type union
select 'Django_migrations', count(*) from Django_migrations union
select 'Django_session', count(*) from Django_session
;

(Sie müssen das letzte union entfernen und das Semikolon am Ende manuell hinzufügen.)

Führen Sie es in psql aus und Sie sind fertig.

            ?column?            | count
--------------------------------+-------
 auth_group_permissions         |     0
 auth_user_user_permissions     |     0
 Django_session                 |  1306
 Django_content_type            |    17
 auth_user_groups               |   162
 Django_admin_log               |  9106
 Django_migrations              |    19
[..]
13
Aur Saraf

Nicht sicher, ob eine Antwort in bash für Sie akzeptabel ist, aber FWIW ...

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
10
Stew-au

Ich verlasse mich normalerweise nicht auf Statistiken, besonders in 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;
7
Yuri Levinsky

Ich erinnere mich nicht an die URL, von der ich das gesammelt habe. Aber hoffe das sollte dir helfen:

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; 

Wenn Sie select count_em_all(); ausführen, erhalten Sie die Zeilenanzahl aller Ihrer Tabellen.

6
Gnanam

Ich habe eine kleine Änderung vorgenommen, um alle Tabellen einzuschließen, auch für nicht öffentliche Tabellen.

CREATE TYPE table_count AS (table_schema TEXT,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 table_schema,table_name
        FROM information_schema.tables
        where table_schema !=''pg_catalog''
          and table_schema !=''information_schema''
        ORDER BY 1,2
        LOOP
            FOR the_count IN EXECUTE ''SELECT COUNT(*) AS "count" FROM '' || t_name.table_schema||''.''||t_name.table_name
            LOOP 
            END LOOP; 

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

benutze select count_em_all(); um es aufzurufen.

Ich hoffe, Sie finden das nützlich. Paul

5
Paul

Einfache zwei Schritte:
(Hinweis: Sie müssen nichts ändern - kopieren und einfügen.)
1. Funktion erstellen

create function 
cnt_rows(schema text, tablename text) returns integer
as
$body$
declare
  result integer;
  query varchar;
begin
  query := 'SELECT count(1) FROM ' || schema || '.' || tablename;
  execute query into result;
  return result;
end;
$body$
language plpgsql;

2. Führen Sie diese Abfrage aus, um die Zeilenanzahl für alle Tabellen abzurufen.

select sum(cnt_rows) as total_no_of_rows from (select 
  cnt_rows(table_schema, table_name)
from information_schema.tables
where 
  table_schema not in ('pg_catalog', 'information_schema') 
  and table_type='BASE TABLE') as subq;

oder

m Zeilenzahlen in Tabellenform zu erhalten

select
  table_schema,
  table_name, 
  cnt_rows(table_schema, table_name)
from information_schema.tables
where 
  table_schema not in ('pg_catalog', 'information_schema') 
  and table_type='BASE TABLE'
order by 3 desc;
4
Raju Sah

Das hat bei mir funktioniert

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

1
Pradeep Maurya

Ich mag Daniel Vérités Antwort . Wenn Sie jedoch keine CREATE-Anweisung verwenden können, können Sie entweder bash solution oder, wenn Sie ein Windows-Benutzer sind, eine Powershell-Anweisung verwenden:

# You don't need this if you have pgpass.conf
$env:PGPASSWORD = "userpass"

# Get table list
$tables = & 'C:\Program Files\PostgreSQL\9.4\bin\psql.exe' -U user -w -d dbname -At -c "select table_name from information_schema.tables where table_type='BASE TABLE' AND table_schema='schema1'"

foreach ($table in $tables) {
    & 'C:\path_to_postresql\bin\psql.exe' -U root -w -d dbname -At -c "select '$table', count(*) from $table"
}
1
CFreitas