[sql] PostgreSQL에서 테이블의 행 수를 찾는 빠른 방법

백분율을 계산하려면 테이블의 행 수를 알아야합니다. 총 개수가 미리 정의 된 일부 상수보다 크면 상수 값을 사용합니다. 그렇지 않으면 실제 행 수를 사용합니다.

사용할 수 있습니다 SELECT count(*) FROM table. 그러나 내 상수 값이 500,000 이고 테이블에 5,000,000,000 개의 행이있는 경우 모든 행을 계산하는 데 많은 시간이 낭비됩니다.

내 상수 값이 초과되는 즉시 계산을 중지 할 수 있습니까?

주어진 한도 미만인 경우에만 정확한 행 수가 필요합니다. 그렇지 않고 카운트가 한계를 초과하면 한계 값을 대신 사용하고 가능한 한 빨리 대답을 원합니다.

이 같은:

SELECT text,count(*), percentual_calculus()
FROM token
GROUP BY text
ORDER BY count DESC;



답변

테이블 에서 행을 계산하는 것은 PostgreSQL에서 느린 것으로 알려져 있습니다. 정확한 숫자를 얻으려면 MVCC 의 특성으로 인해 전체 행 수를 계산해야합니다 . 귀하의 경우처럼 개수가 정확할 필요 가 없는 경우이를 극적으로 가속화 있는 방법 있습니다.

정확한 개수 를 얻는 대신 ( 큰 테이블에서는 느림 ) :

SELECT count(*) AS exact_count FROM myschema.mytable;

다음과 같은 가까운 추정치를 얻습니다 ( 매우 빠름 ).

SELECT reltuples::bigint AS estimate FROM pg_class where relname='mytable';

추정치가 얼마나 가까운지는 ANALYZE충분히 실행했는지에 따라 다릅니다 . 일반적으로 매우 가깝습니다. PostgreSQL Wiki FAQ를
참조하십시오 .
또는 count (*) 성능에 대한 전용 위키 페이지 .

더 나은

PostgreSQL의 위키의 문서 되어 있었다 약간의 실수 . 하나의 데이터베이스에 다른 스키마에 같은 이름의 여러 테이블이있을 수 있다는 가능성을 무시했습니다. 이를 설명하려면 :

SELECT c.reltuples::bigint AS estimate
FROM   pg_class c
JOIN   pg_namespace n ON n.oid = c.relnamespace
WHERE  c.relname = 'mytable'
AND    n.nspname = 'myschema'

또는 더 나은

SELECT reltuples::bigint AS estimate
FROM   pg_class
WHERE  oid = 'myschema.mytable'::regclass;

더 빠르고 간단하고 안전하며 우아합니다. 객체 식별자 유형 에 대한 설명서를 참조하십시오 .

to_regclass('myschema.mytable')Postgres 9.4 이상에서 사용하면 잘못된 테이블 이름에 대한 예외를 방지 할 수 있습니다.

TABLESAMPLE SYSTEM (n) Postgres 9.5 이상

SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);

@a_horse commented 와 같이 SELECT명령에 대해 새로 추가 된 절 pg_class은 어떤 이유로 든 통계 가 최신 상태가 아닌 경우 유용 할 수 있습니다 . 예를 들면 :

  • 달리지 않습니다 autovacuum.
  • INSERT또는 DELETE.
  • TEMPORARY 테이블 ( autovacuum ).

이것은 임의의 n % ( 1예제에서) 블록 선택 만보고 그 안에있는 행을 계산합니다. 더 큰 샘플은 비용을 증가시키고 오류를 줄입니다. 정확도는 더 많은 요인에 따라 달라집니다.

  • 행 크기 분포. 주어진 블록이 일반적인 행보다 더 넓게 유지되는 경우 개수는 평소보다 낮습니다.
  • 데드 튜플 또는 FILLFACTOR 블록 당 점유 공간. 테이블 전체에 고르지 않게 분산 된 경우 예상치가 다를 수 있습니다.
  • 일반적인 반올림 오류.

대부분의 경우 추정치 pg_class 가 더 빠르고 정확합니다.

실제 질문에 대한 답변

먼저, 총 개수가 미리 정의 된 상수보다 큰 경우 해당 테이블의 행 수를 알아야합니다.

그리고 그것이 …

… 카운트가 내 상수 값을 통과하는 순간에 가능하며, 카운팅을 중지합니다 (카운팅을 완료하여 행 개수가 더 크다는 것을 알리기 위해 기다리지 않음).

예. 다음 과 함께 하위 쿼리를LIMIT 사용할 수 있습니다 .

SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;

포스트 그레스는 실제로 계산 중지 , 당신이 얻을 주어진 한계 너머를 정확하고 현재 까지 대한 수를 N 과, (예의 500000) 행을 N 그렇지. pg_class하지만 의 추정치만큼 빠르지는 않습니다.


답변

postgres 앱에서 다음을 실행하여 한 번 수행했습니다.

EXPLAIN SELECT * FROM foo;

그런 다음 정규식 또는 유사한 논리를 사용하여 출력을 검사합니다. 간단한 SELECT *의 경우 출력의 첫 번째 줄은 다음과 같아야합니다.

Seq Scan on uids  (cost=0.00..1.21 rows=8 width=75)

rows=(\d+)값을 반환 될 행 수의 대략적인 추정치로 사용할 수 있으며 SELECT COUNT(*), 추정치가 임계 값의 1.5 배 (또는 애플리케이션에 적합하다고 생각하는 숫자)보다 작은 경우 에만 실제를 수행 할 수 있습니다.

쿼리의 복잡성에 따라이 숫자는 점점 더 정확하지 않을 수 있습니다. 사실, 제 응용 프로그램에서 조인과 복잡한 조건을 추가함에 따라 100의 거듭 제곱 내에서 얼마나 많은 행을 반환했는지 알기조차도 너무 정확하지 않아서 그 전략을 포기해야했습니다.

그러나 쿼리가 Pg가 합리적인 오차 범위 내에서 반환 할 행 수를 예측할 수있을만큼 충분히 간단하다면 작동 할 수 있습니다.


답변

이 블로그에서 가져온 참조입니다.

아래에서 쿼리를 사용하여 행 수를 찾을 수 있습니다.

pg_class 사용 :

 SELECT reltuples::bigint AS EstimatedCount
    FROM   pg_class
    WHERE  oid = 'public.TableName'::regclass;

pg_stat_user_tables 사용 :

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


답변

Oracle에서는 rownum반환되는 행 수를 제한하는 데 사용할 수 있습니다 . 비슷한 구조가 다른 SQL에도 존재한다고 생각합니다. 따라서 제공 한 예제의 경우 반환되는 행 수를 500001로 제한하고 count(*)then을 적용 할 수 있습니다 .

SELECT (case when cnt > 500000 then 500000 else cnt end) myCnt
FROM (SELECT count(*) cnt FROM table WHERE rownum<=500001)


답변

텍스트 열의 너비는 얼마입니까?

GROUP BY를 사용하면 데이터 스캔 (최소한 인덱스 스캔)을 피하기 위해 할 수있는 일이별로 없습니다.

다음을 추천합니다.

  1. 가능하면 스키마를 변경하여 텍스트 데이터의 중복을 제거하십시오. 이렇게하면 ‘many’테이블의 좁은 외래 키 필드에서 개수가 계산됩니다.

  2. 또는 텍스트의 HASH로 생성 된 열을 생성 한 다음 해시 열로 GROUP BY를 생성합니다. 다시 말하지만 이것은 워크로드를 줄이는 것입니다 (좁은 열 인덱스를 통해 스캔).

편집하다:

원래 질문이 편집 내용과 일치하지 않습니다. GROUP BY와 함께 사용할 때 COUNT가 전체 테이블의 항목 수가 아니라 그룹당 항목 수를 반환한다는 것을 알고 있는지 확실하지 않습니다.


답변

아래 쿼리로 개수를 가져올 수 있습니다 (* 또는 열 이름없이).

select from table_name;


답변

SQL Server (2005 이상)의 경우 빠르고 안정적인 방법은 다음 과 같습니다.

SELECT SUM (row_count)
FROM sys.dm_db_partition_stats
WHERE object_id=OBJECT_ID('MyTableName')
AND (index_id=0 or index_id=1);

sys.dm_db_partition_stats에 대한 자세한 내용은 MSDN에 설명되어 있습니다.

쿼리는 파티션을 나눈 테이블의 모든 부분에서 행을 추가합니다.

index_id = 0은 정렬되지 않은 테이블 (힙)이고 index_id = 1은 정렬 된 테이블 (클러스터형 인덱스)입니다.

더 빠른 (그러나 신뢰할 수없는) 방법이 여기 에 자세히 설명되어 있습니다.