Ik ben op zoek naar een manier om het aantal rijen voor al mijn tabellen in Postgres te vinden. Ik weet dat ik dit tafel voor tafel kan doen met:
SELECT count(*) FROM table_name;
maar ik zou graag het aantal rijen voor alle tafels willen zien en dan op basis daarvan bestellen om een idee te krijgen van hoe groot al mijn tafels zijn.
Antwoord 1, autoriteit 100%
Er zijn drie manieren om dit soort telling te krijgen, elk met hun eigen afwegingen.
Als je een echte telling wilt, moet je de SELECT-instructie uitvoeren zoals je die voor elke tabel hebt gebruikt. Dit komt omdat PostgreSQL de zichtbaarheidsinformatie van rijen in de rij zelf bewaart, niet ergens anders, dus een nauwkeurige telling kan alleen relatief zijn aan een transactie. U krijgt een telling van wat die transactie ziet op het moment dat deze wordt uitgevoerd. Je zou dit kunnen automatiseren zodat het tegen elke tabel in de database wordt uitgevoerd, maar waarschijnlijk heb je dat niveau van nauwkeurigheid niet nodig of wil je zo lang wachten.
De tweede benadering merkt op dat de verzamelaar van statistieken op enig moment ongeveer bijhoudt hoeveel rijen “live” (niet verwijderd of verouderd door latere updates) zijn. Deze waarde kan iets afwijken bij zware activiteit, maar is over het algemeen een goede schatting:
SELECT schemaname,relname,n_live_tup
FROM pg_stat_user_tables
ORDER BY n_live_tup DESC;
Dat kan je ook laten zien hoeveel rijen dood zijn, wat zelf een interessant getal is om te controleren.
De derde manier is om op te merken dat het systeem ANALYZE-commando, dat vanaf PostgreSQL 8.3 regelmatig wordt uitgevoerd door het autovacuümproces om tabelstatistieken bij te werken, ook een rijschatting berekent. Je kunt die zo pakken:
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;
Welke van deze zoekopdrachten het beste is om te gebruiken, is moeilijk te zeggen. Normaal gesproken neem ik die beslissing op basis van of er meer nuttige informatie is die ik ook wil gebruiken in pg_class of in pg_stat_user_tables. Voor basisteldoeleinden, gewoon om te zien hoe groot dingen in het algemeen zijn, moeten beide nauwkeurig genoeg zijn.
Antwoord 2, autoriteit 17%
Hier is een oplossing waarvoor geen functies nodig zijn om een nauwkeurige telling voor elke tafel te krijgen:
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
voert de doorgegeven SQL-query uit en retourneert een XML met het resultaat (het aantal rijen voor die tabel). De buitenste xpath()
zal dan de telinformatie uit die XML extraheren en deze omzetten in een getal
De afgeleide tabel is niet echt nodig, maar maakt de xpath()
een beetje gemakkelijker te begrijpen – anders zou de hele query_to_xml()
moeten worden doorgegeven aan de xpath()
functie.
Antwoord 3, autoriteit 5%
Bekijk Het antwoord van Greg Smithvoor schattingen.
Om exacte aantallen te krijgen, worden de andere antwoorden tot nu toe geplaagd door enkele problemen, waarvan sommige ernstig zijn (zie hieronder). Hier is een versie die hopelijk beter is:
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;
Er is een schemanaam nodig als parameter, of public
als er geen parameter is opgegeven.
Als u wilt werken met een specifieke lijst met schema’s of een lijst die uit een query komt zonder de functie te wijzigen, kan deze vanuit een query als volgt worden aangeroepen:
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;
Dit levert een uitvoer van 3 kolommen op met het schema, de tabel en het aantal rijen.
Hier zijn enkele problemen in de andere antwoorden die deze functie vermijdt:
-
Tabel- en schemanamen mogen niet in uitvoerbare SQL worden geïnjecteerd zonder aanhalingstekens, ofwel met
quote_ident
of met de modernere functieformat()
met zijn%I
opmaaktekenreeks. Anders kan een kwaadwillende zijn tafel de naamtablename;DROP TABLE other_table
geven, wat perfect geldig is als tafelnaam. -
Zelfs zonder de SQL-injectie en problemen met grappige tekens, kan de tabelnaam voorkomen in varianten die per geval verschillen. Als een tabel
abcd
heet en een andereabcd
, moet deSELECT count(*) FROM...
een naam tussen aanhalingstekens gebruiken, anders wordt het slaabcd
over en telabcd
twee keer. De indeling%I
doet dit automatisch. -
information_schema.tables
vermeldt naast tabellen ook aangepaste samengestelde typen, zelfs wanneer table_type'BASE TABLE'
(!) is. Als gevolg hiervan kunnen weinformation_schema.tables
niet herhalen, anders lopen we het risico dat weselect count(*) from name_of_composite_type
hebben en dat zou mislukken. OTOHpg_class where relkind='r'
altijd goed zou moeten werken. -
Het type COUNT() is
bigint
, nietint
. Er kunnen tabellen met meer dan 2,15 miljard rijen bestaan (het is echter een slecht idee om er een telling(*) op uit te voeren). -
Er hoeft geen permanent type te worden gemaakt voor een functie om een resultatenset met meerdere kolommen te retourneren.
RETURNS TABLE(definition...)
is een beter alternatief.
Antwoord 4, autoriteit 3%
Als u mogelijk verouderde gegevens niet erg vindt, kunt u toegang tot dezelfde statistieken die worden gebruikt door de query-optimizer.
Zoiets als:
SELECT relname, n_tup_ins - n_tup_del as rowcount FROM pg_stat_all_tables;
Antwoord 5
Dit werkte voor mij
SELECTEER schemanaam,relnaam,n_live_tup VANAF pg_stat_user_tables ORDER OP
n_live_tup DESC;
Antwoord 6
Ik weet de URL niet meer van waaruit ik dit heb verzameld. Maar ik hoop dat dit je zou moeten helpen:
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;
Als u select count_em_all();
uitvoert, krijgt u het aantal rijen van al uw tabellen.
Antwoord 7
Ik heb een kleine variatie gemaakt om alle tabellen op te nemen, ook voor niet-openbare 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;
gebruik select count_em_all();
om het aan te roepen.
Ik hoop dat je dit nuttig vindt.
Paul
Antwoord 8
Geëxtraheerd uit mijn commentaar in het antwoord van GregSmith om het leesbaarder te maken:
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;
Met dank aan @a_horse_with_no_name
Antwoord 9
U kunt deze zoekopdracht gebruiken om alle tafelnamen met hun tellingen te genereren
select ' select '''|| tablename ||''', count(*) from ' || tablename ||'
union' from pg_tables where schemaname='public';
het resultaat van de bovenstaande zoekopdracht is
select 'dim_date', count(*) from dim_date union
select 'dim_store', count(*) from dim_store union
select 'dim_product', count(*) from dim_product union
select 'dim_employee', count(*) from dim_employee union
U moet de laatste unie verwijderen en de puntkomma aan het einde toevoegen !!
select 'dim_date', count(*) from dim_date union
select 'dim_store', count(*) from dim_store union
select 'dim_product', count(*) from dim_product union
select 'dim_employee', count(*) from dim_employee **;**
RUN !!!
Antwoord 10
Hier is een veel eenvoudigere manier.
tables="$(echo '\dt' | psql -U "${PGUSER}" | tail -n +4 | head -n-2 | tr -d ' ' | cut -d '|' -f2)"
for table in $tables; do
printf "%s: %s\n" "$table" "$(echo "SELECT COUNT(*) FROM $table;" | psql -U "${PGUSER}" | tail -n +3 | head -n-2 | tr -d ' ')"
done
uitvoer zou er zo uit moeten zien
auth_group: 0
auth_group_permissions: 0
auth_permission: 36
auth_user: 2
auth_user_groups: 0
auth_user_user_permissions: 0
authtoken_token: 2
django_admin_log: 0
django_content_type: 9
django_migrations: 22
django_session: 0
mydata_table1: 9011
mydata_table2: 3499
u kunt het gedeelte psql -U "${PGUSER}"
zo nodig bijwerken om toegang te krijgen tot uw database
merk op dat de syntaxis head -n-2
mogelijk niet werkt in macOS, u kunt waarschijnlijk gewoon een andere implementatiedaar
Getest op psql (PostgreSQL) 11.2 onder CentOS 7
als je het gesorteerd wilt hebben op tabel, wikkel het dan gewoon met sort
for table in $tables; do
printf "%s: %s\n" "$table" "$(echo "SELECT COUNT(*) FROM $table;" | psql -U "${PGUSER}" | tail -n +3 | head -n-2 | tr -d ' ')"
done | sort -k 2,2nr
uitvoer;
mydata_table1: 9011
mydata_table2: 3499
auth_permission: 36
django_migrations: 22
django_content_type: 9
authtoken_token: 2
auth_user: 2
auth_group: 0
auth_group_permissions: 0
auth_user_groups: 0
auth_user_user_permissions: 0
django_admin_log: 0
django_session: 0
Antwoord 11
Ik vind het antwoordvan Daniel Vérité goed.
Maar als u geen CREATE-instructie kunt gebruiken, kunt u ofwel een bash-oplossinggebruiken of, als u een Windows-gebruiker bent , een powershell:
# 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"
}
Antwoord 12
Ik wilde het totaal van alle tabellen + een lijst met tabellen met hun tellingen. Een beetje zoals een prestatiegrafiek van waar de meeste tijd aan werd besteed
WITH results AS (
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'
GROUP BY schemaname, relname, reltuples
)
SELECT * FROM results
UNION
SELECT 'all' AS schemaname, 'all' AS relname, SUM(reltuples) AS "reltuples" FROM results
ORDER BY reltuples DESC
Je kunt natuurlijk ook een LIMIT
-clausule op de resultaten in deze versie zetten, zodat je zowel de grootste n
overtreders als het totaal krijgt.
Een ding dat hierbij moet worden opgemerkt, is dat u het een tijdje moet laten staan na bulkimport. Ik heb dit getest door gewoon 5000 rijen toe te voegen aan een database over verschillende tabellen met behulp van echte importgegevens. Het toonde 1800 records gedurende ongeveer een minuut (waarschijnlijk een configureerbaar venster)
Dit is gebaseerd op https://stackoverflow.com/a/2611745/1548557werk, dus bedankt en herkenning voor de zoekopdracht die moet worden gebruikt binnen de CTE
13
Hieronder vraag geeft ons rijtelling en -grootte voor elke tabel
Selecteer Table_schema, TACE_NAME,
pg_relation_size (‘”‘ || table_schema || ‘”. “‘ || tabel_name || ‘”‘) / 1024/1024 size_mb,
(XPath (‘/ rij / C / Text ()’, query_to_xml (formaat (‘selecteer telling (*) als C van% I.% I’, TACE_SCHEMA, TACE_NAME),
false, true, ”)))))) [1] :: Tekst :: int als rows_n
van informatie_schema.tables
bestel op maat_mb Desc;