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


107

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

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

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

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

이 같은:

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

5
n = constant + 1 인 처음 n 개의 행 을 선택하려고 할 수 없습니까? 만약 그것이 당신의 상수보다 더 많이 반환한다면, 당신은 당신의 상수를 사용해야한다는 것을 알고 있습니다. 그렇지 않다면 당신은 좋은 것입니까?
gddc

테이블에 ID 또는 자동 증가 필드가 있습니까
Sparky

1
@Sparky : 시퀀스 지원 PK는 연속성이 보장되지 않으며 행이 삭제되거나 중단 된 트랜잭션으로 인해 간격이 발생할 수 있습니다.
mu가 너무 짧습니다.

업데이트가 원래 질문과 모순되는 것 같습니다. 정확한 행 수를 알아야합니까, 아니면 임계 값 미만인 경우에만 정확한 수를 알아야합니까?
Flimzy 2011 년

1
@ RenatoDinhaniConceição : 해결하려는 정확한 문제를 설명해 주 시겠습니까? 아래 내 대답이 처음에 귀하의 문제라고 말한 것을 해결한다고 생각합니다. 업데이트는 count (*) 및 다른 많은 필드를 원하는 것처럼 보이게합니다. 당신이하려는 일을 정확히 설명 할 수 있다면 도움이 될 것입니다. 감사.
Ritesh 2011 년

답변:


224

테이블 에서 행을 계산하는 것은 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하지만 의 추정치만큼 빠르지는 않습니다.


8
결국 향상된 쿼리로 Postgres Wiki 페이지를 업데이트했습니다.
Erwin Brandstetter 2013-06-11

5
9.5으로 추정의 빠른을 얻는 것은 사용 가능해야한다 tablesample예 : 절select count(*) * 100 as cnt from mytable tablesample system (1);
a_horse_with_no_name

1
@JeffWidman : 이러한 모든 추정치 다양한 이유로 실제 행 수보다 클 있습니다. 특히 그 동안 삭제가 발생했을 수 있습니다.
Erwin Brandstetter 2015

2
@ErwinBrandstetter는이 질문이 오래되었다는 것을 알고 있지만 쿼리를 하위 쿼리로 래핑하면 제한이 여전히 효율적이거나 전체 하위 쿼리가 실행 된 다음 외부 쿼리에서 제한됩니다. SELECT count(*) FROM (Select * from (SELECT 1 FROM token) query) LIMIT 500000) limited_query;(나는 이미 그것에 제한 조항이있을 수 있습니다 임의의 쿼리 카운트 얻기 위해 노력하고 있기 때문에 물어)
니콜라스 Erdenberger

1
@NicholasErdenberger : 하위 쿼리에 따라 다릅니다. Postgres는 어쨌든 제한보다 더 많은 행을 고려해야 할 수도 있습니다 (예 ORDER BY something: 인덱스를 사용할 수 없거나 집계 함수와 함께). 그 외에도 하위 쿼리에서 제한된 수의 행만 처리됩니다.
어윈 Brandstetter

12

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가 합리적인 오차 범위 내에서 반환 할 행 수를 예측할 수있을만큼 충분히 간단하다면 작동 할 수 있습니다.


2

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

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

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;

이 방법이 작동하려면 테이블을 VACUUM ANALYZE해야합니다.
William Abma 19

1

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)

1
SELECT count (*) cnt FROM table은 항상 단일 행을 반환합니다. LIMIT가 거기에 어떤 이점을 추가 할 것인지 확실하지 않습니다.
Chris Bednarski 2011 년

@ChrisBednarski : Oracle db에서 내 대답의 Oracle 버전을 확인했습니다. 그것은 훌륭하게 작동하고 OP의 문제라고 생각했던 것을 해결합니다 ( count(*)rownum을 사용하면 0.05 초 , rownum을 사용하지 않고 1 초). 예, SELECT count(*) cnt FROM table항상 1 행을 반환하지만 LIMIT 조건에서는 테이블 크기가 500000 이상이면 "500001"을 반환하고 테이블 크기가 <= 500000이면 <size>를 반환합니다.
Ritesh

2
PostgreSQL 쿼리는 완전 말도 안됩니다. 구문 적으로나 논리적으로 잘못되었습니다. 수정하거나 제거하십시오.
Erwin Brandstetter 2011 년

@ErwinBrandstetter : 제거되었습니다. PostgreSQL이 그렇게 다르다는 것을 몰랐습니다.
Ritesh 2011 년

@allrite : 의심 할 여지없이 Oracle 쿼리가 제대로 작동합니다. 하지만 LIMIT는 다르게 작동합니다. 기본 수준에서는 데이터베이스 엔진이 쿼리하는 행 수가 아니라 클라이언트에 반환되는 행 수를 제한합니다.
Chris Bednarski 2011 년

0

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

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

다음을 추천합니다.

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

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

편집하다:

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


0

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

select from table_name;

2
이것은보다 빠르지 않은 것 같습니다 count(*).
화창한

-3

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은 정렬 된 테이블 (클러스터형 인덱스)입니다.

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

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