Postgres에서 모든 테이블의 행 수를 어떻게 찾습니까?


395

Postgres의 모든 테이블에 대한 행 수를 찾는 방법을 찾고 있습니다. 나는이 테이블을 한 번에 하나씩 할 수 있다는 것을 알고있다.

SELECT count(*) FROM table_name;

그러나 모든 테이블의 행 수를 확인한 다음 순서대로 정렬하여 내 모든 테이블의 크기를 알 수 있습니다.

답변:


582

이러한 종류의 카운트를 얻는 방법에는 세 가지가 있으며 각각 고유 한 장단점이 있습니다.

실제 개수를 원하면 각 테이블에 대해 사용한 것과 같은 SELECT 문을 실행해야합니다. PostgreSQL은 행 가시성 정보를 다른 곳이 아닌 행 자체에 유지하므로 정확한 수는 일부 트랜잭션에만 관련 될 수 있기 때문입니다. 트랜잭션이 실행될 때 해당 트랜잭션에 표시되는 개수를 얻습니다. 데이터베이스의 모든 테이블에 대해 실행되도록 자동화 할 수는 있지만 그 정도의 정확도가 필요하지 않거나 오랫동안 기다릴 필요가 있습니다.

두 번째 방법은 통계 수집기가 언제든지 "실제"행 수 (추후 업데이트로 삭제 또는 폐기되지 않음)를 대략적으로 추적합니다. 이 값은 활동이 많을 때 약간 벗어날 수 있지만 일반적으로 좋은 추정치입니다.

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

또한 얼마나 많은 행이 죽었는지 보여줄 수 있습니다.

세 번째 방법은 테이블 통계를 업데이트하기 위해 PostgreSQL 8.3에서 정기적으로 autovacuum 프로세스에 의해 실행되는 시스템 ANALYZE 명령이 행 추정값을 계산한다는 것입니다. 당신은 이것처럼 이것을 잡을 수 있습니다 :

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;

이러한 쿼리 중 어느 것이 더 나은지를 말하기는 어렵습니다. 일반적으로 나는 pg_class 내부 또는 pg_stat_user_tables 내부에서 더 유용한 정보가 있는지 여부에 따라 결정합니다. 기본적인 계산의 목적으로, 일반적으로 큰 것이 얼마나 큰지 알기 위해서는 충분히 정확해야합니다.


2
완료를 위해 첫 번째 옵션에 이것을 추가하십시오 (감사합니다 @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;
estani

1
@Greg Smith 어떤 버전을 소개 n_live_tup했습니까? Redshift 데이터베이스에 해당 열이 없습니다. Postgres 8.0.2의 파생물입니다.
Iain Samuel McLean Elder 's

1
실행 된 적이 없기 때문에 '두 번째 접근'쿼리 (를 사용하여 pg_stat_user_tables)는 대부분 0을 반환했습니다 . 모든 스키마 / 테이블에서 실행 하고 응답을 영원히 기다리기 보다는 먼저 'third approach'를 사용하여 결과를 확인했으며 (을 사용하여 ) 매우 정확한 수를 반환했습니다. n_live_tupANALYZEANALYZEpg_class
Brian D

@BrianD, "
analyzedb

69

각 테이블의 정확한 개수를 얻기 위해 함수가 필요없는 솔루션은 다음과 같습니다.

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전달 된 SQL 쿼리를 실행하고 결과 (해당 테이블의 행 수)와 함께 XML을 반환합니다. xpath()그런 다음 외부 는 해당 XML에서 카운트 정보를 추출하여 숫자로 변환합니다.

파생 테이블은 실제로 필요하지는 않지만 xpath()조금 이해하기 쉽게 만듭니다. 그렇지 않으면 전체 query_to_xml()xpath()함수에 전달해야합니다 .


3
매우 영리한. 안타깝습니다 query_to_jsonb().
클라인

@a_horse_with_no_name, 실행하는 동안 사용량이 많고 거대한 테이블에서 성능 문제가 발생합니까?
스파이크

@Spike : 성능 문제가 무엇에 비해? 주요 성능 병목 현상은 select count(*)모든 테이블에서 실행 됩니다.
a_horse_with_no_name

1 억 레코드에 대해 x_path 함수를 실행하여 @a_horse_with_no_name
스파이크

@Spike :이 xpath()함수는 단일 행 에만 적용됩니다 .count(*)
a_horse_with_no_name

24

견적을 얻으려면 Greg Smith의 답변을 참조하십시오 .

정확한 수를 얻으려면 지금까지 다른 대답에는 몇 가지 문제가 있으며 그중 일부는 심각합니다 (아래 참조). 더 나은 버전이 있습니다.

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;

스키마 이름을 매개 변수로 사용하거나 public매개 변수를 지정하지 않은 경우를 사용합니다.

함수를 수정하지 않고 특정 스키마 목록이나 쿼리에서 오는 목록으로 작업하려면 다음과 같이 쿼리 내에서 호출 할 수 있습니다.

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;

스키마, 테이블 및 행 수와 함께 3 열 출력이 생성됩니다.

이제이 함수가 피하는 다른 답변의 몇 가지 문제가 있습니다.

  • 테이블 및 스키마 이름은 형식 문자열이있는 quote_ident최신 format()기능을 사용 하거나 사용 하지 않고 따옴표없이 실행 가능한 SQL에 삽입하면 안됩니다 %I. 그렇지 않으면 일부 악의적 인 사람이 자신 tablename;DROP TABLE other_table의 테이블 이름을 테이블 이름으로 완벽하게 사용할 수 있습니다 .

  • SQL 삽입 및 재미있는 문자 문제가 없어도 테이블 이름은 대소 문자가 다른 변형으로 존재할 수 있습니다. 테이블의 이름은 경우 ABCD와 다른 하나 abcd는이 SELECT count(*) FROM...그렇지 인용 된 이름을 사용해야은 건너 뛸 ABCD카운트 abcd를 두 번 누릅니다. %I형식이 자동으로이 작업을 수행합니다.

  • information_schema.tablestable_type이 'BASE TABLE'(!) 인 경우에도 테이블 외에 사용자 정의 복합 유형을 나열합니다 . 결과적으로, 우리는 반복 할 수 없으며 information_schema.tables그렇지 않으면 우리는 가질 위험이 select count(*) from name_of_composite_type있으며 실패 할 것입니다. OTOH pg_class where relkind='r'는 항상 잘 작동합니다.

  • COUNT의 종류는 ()이다 bigint,하지 int. 21 억 5 천 개가 넘는 행이있는 테이블이 존재할 수 있습니다.

  • 함수가 여러 열이있는 결과 집합을 반환하기 위해 영구 유형을 만들 필요는 없습니다. RETURNS TABLE(definition...)더 나은 대안입니다.


18

잠재적으로 오래된 데이터가 마음에 들지 않으면 쿼리 최적화 프로그램에서 사용하는 것과 동일한 통계에 액세스 할 수 있습니다 .

다음과 같은 것 :

SELECT relname, n_tup_ins - n_tup_del as rowcount FROM pg_stat_all_tables;

@mlissner : 자동 진공 간격이 너무 길거나 ANALYZE테이블에서 매뉴얼 을 실행하지 않으면 통계가 사라질 수 있습니다. 데이터베이스로드 및 데이터베이스 구성 방법에 대한 질문입니다 (통계가 더 자주 업데이트되면 통계가 더 정확하지만 런타임 성능이 저하 될 수 있음). 궁극적으로 정확한 데이터를 얻는 유일한 방법 select count(*) from table은 모든 테이블에 대해 실행 하는 것입니다.
ig0774

17

헤 로쿠의 느린 행 카운터가 새로 고침 될 때까지 기다릴 수없고 어떤 헤 로쿠 계획이 필요한지를 평가하려는 사람들에게 해킹 된 실질적인 답변 :

기본적으로 당신이 실행하려는 \dt에서 psql, (가 같이 표시됩니다 좋아하는 텍스트 편집기로 결과를 복사 :

 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

), 정규식 검색을 실행하고 다음과 같이 바꾸십시오.

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

에:

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

그러면 다음과 매우 비슷한 결과가 나타납니다.

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
;

(마지막을 제거 union하고 끝에 수동으로 세미콜론을 추가해야합니다)

그것을 실행 psql하고 완료했습니다.

            ?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
[..]

나는이 생각처럼
GuilPejon

: 아톰, 나는 검색을 정규식과 같은 대체했다 select '$1', count(*) from $1 union/g

또한 게시물에 "노조를 제거하고 끝에 세미콜론을 추가해야합니다."라고 말합니다. 이것은 오타입니다. 맨 끝에 세미콜론 ( ) 을 제거하고 /g(유지 union) 해야합니다 ;. union세미콜론 앞의 마지막을 제거하는 것을 잊지 마십시오 .

1
"마지막을 제거하는 것을 잊지 마십시오 union세미콜론 전에 것은"나는 :) 의미 명확히하기 위해 "마지막"이라는 단어를 추가 것입니다
마차부 사라 프에게

10

bash 의 대답 이 당신에게 맞는지 확실하지 않지만 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

7
본질적으로 이것은 select count(*) from table_name;OP 에서 동일하게 요약됩니다 !
Noach Magedman

8

나는 보통 통계, 특히 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;

이것은 좋지만 첫 번째 쿼리에는 rownum 값에 대한 스키마도 포함되어야합니다. 다른 스키마에 충돌하는 이름이 있으면 예상대로 작동하지 않습니다. 따라서 쿼리 의이 부분은 dsql2('select count(*) from livescreen.'||table_name)자체 기능으로 전환 될 수 있거나 더 좋아 보여야합니다 .
jakub-olczyk 2018 년

6

이것을 수집 한 URL이 기억 나지 않습니다. 그러나 이것이 도움이되기를 바랍니다.

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; 

실행 select count_em_all();하면 모든 테이블의 행 수를 얻을 수 있습니다.


1
quote_ident(t_name.relname)비정상적인 이름 (예 : "column-name")을 올바르게 지원하려면 열 이름 (예 :)을 인용하는 것이 좋습니다 .
gorsky

나중에 삭제하려면 : DROP FUNCTION count_em_all ();
Aalex Gabi

오류가 발생했습니다 : select count_em_all (); 오류 : "group"또는 그 근처의 구문 오류 LINE 1 : SELECT COUNT () AS "count"FROM 그룹 ^ QUERY : SELECT COUNT () AS "count"FROM 그룹 CONTEXT : PL / pgSQL 함수 count_em_all () 18 번 FOR EXECUTE 성명서
Aalex Gabi

큰! 종류 선택하기 - SELECT * FROM count_em_all() as r ORDER BY r.num_rows DESC;
Ken4scholars

6

간단한 두 단계 :
(참고 : 아무것도 변경할 필요가 없습니다-그냥 붙여 넣기를 복사 하십시오 )
1. 함수 만들기

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.이 쿼리를 실행하여 모든 테이블의 행 수를 가져옵니다.

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;

또는

테이블 단위로 행 개수를 얻으려면

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;

5

비공개 테이블에도 모든 테이블을 포함하도록 약간 변형했습니다.

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; 

select count_em_all();그것을 호출하는 데 사용 합니다.

이 유용한 정보를 찾으십시오. 폴


오류 : "r.table_schema"는 알려진 변수가 아닙니다
slashdottir

2

이것은 나를 위해 일했다

pg_stat_user_tables에서 schemaname, relname, n_live_tup을 선택하십시오. ORDER BY n_live_tup DESC;


1

나는 Daniel Vérité의 답변을 좋아 합니다. 그러나 CREATE 문을 사용할 수 없으면 bash 솔루션을 사용 하거나 Windows 사용자 인 경우 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"
}

0

모든 테이블의 합계 + 개수가있는 테이블 목록을 원했습니다. 대부분의 시간이 소요 된 성능 차트와 비슷합니다.

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

물론 LIMIT이 버전의 결과에 대해서도 조항을 추가 할 수 있으므로 n전체적으로뿐만 아니라 가장 큰 범죄자 를 얻을 수 있습니다.

이것에 대해 주목해야 할 한 가지는 대량 수입 후 잠시 동안 그대로 두어야한다는 것입니다. 실제 가져 오기 데이터를 사용하여 여러 테이블의 데이터베이스에 5000 행을 추가하여 이것을 테스트했습니다. 약 1 분 동안 1800 개의 레코드를 표시했습니다 (아마도 구성 가능한 창).

이것은 https://stackoverflow.com/a/2611745/1548557 작업을 기반으로 하므로 쿼리가 CTE 내에서 사용하도록 감사합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.