web-dev-qa-db-ja.com

PostgreSQLのテーブルの行数をすばやく発見する方法

パーセンテージを計算するには、テーブル内の行数を知る必要があります。合計カウントが定義済みの定数よりも大きい場合、定数値を使用します。それ以外の場合は、実際の行数を使用します。

SELECT count(*) FROM tableを使用できます。しかし、定数値が500,0で、テーブルに5,000,000,0行がある場合、すべての行をカウントすると多くの時間が無駄になります。

定数値を超えるとすぐにカウントを停止できますか?

指定された制限を下回っている場合にのみ、正確な行数が必要です。それ以外の場合、カウントが制限を超えている場合は、代わりに制限値を使用し、できるだけ早く答えを求めます。

このようなもの:

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

bigテーブルの行のカウントは、PostgreSQLでは遅いことが知られています。正確な数を取得するには、 [〜#〜] mvcc [〜#〜] の性質により、行を完全にカウントする必要があります。 これを劇的にスピードアップする方法がありますカウントが not でなければならない場合 exact あなたの場合のようです。

exactカウント(大きなテーブルでは slow )を取得する代わりに:

_SELECT count(*) AS exact_count FROM myschema.mytable;
_

次のような近い見積もりが得られます( extremely fast ):

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

見積もりがどれだけ近いかは、 ANALYZE で十分かどうかによって異なります。それは通常非常に近いです。
PostgreSQL Wiki FAQ をご覧ください。
または count(*)パフォーマンス専用のwikiページ

まだ良い

PostgreSQL Wikiの記事  少しずさんなでした。異なるスキーマにある1つのデータベースに同じ名前のテーブルが複数存在する可能性を無視しました。それを説明するには:

_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;
_

より速く、よりシンプルに、より安全に、よりエレガントに。 Object Identifier Types のマニュアルを参照してください。

Postgres 9.4以降でto_regclass('myschema.mytable')を使用して、無効なテーブル名の例外を回避します。


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;
_

Postgres 実際にカウントを停止する指定された制限を超えると、正確で現在最大n行(例では500000)までのカウントを取得し、 nそれ以外の場合。ただし、_pg_class_の推定ほど高速ではありません。

184

私はこれをpostgresアプリで1回実行しました:

_EXPLAIN SELECT * FROM foo;
_

次に、正規表現または同様のロジックで出力を調べます。単純なSELECT *の場合、出力の最初の行は次のようになります。

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

返される行数のおおよその推定値としてrows=(\d+)値を使用し、推定値がたとえば1.5x未満の場合にのみ実際のSELECT COUNT(*)を実行できますしきい値(または、アプリケーションにとって意味があると思われる数値)。

クエリの複雑さに応じて、この数はますます正確でなくなる可能性があります。実際、私のアプリケーションでは、結合と複雑な条件を追加すると、非常に不正確になり、100の累乗内で何行返されるかを知ることすらまったく価値がなくなったため、その戦略を放棄する必要がありました。

ただし、Pgが妥当なエラーの範囲内で返す行数を予測できるほど単純なクエリであれば、それが機能する可能性があります。

10
Flimzy

以下のクエリ(*または列名なし)でカウントを取得できます。

select from table_name;
1
SuperNova

Oracleでは、rownumを使用して、返される行の数を制限できます。他のSQLにも同様の構造が存在すると推測しています。したがって、指定した例では、返される行の数を500001に制限し、count(*)を適用することができます。

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

テキスト列の幅はどれくらいですか?

GROUP BYでは、データスキャン(少なくともインデックススキャン)を回避するためにできることはあまりありません。

私はお勧めします:

  1. 可能であれば、スキーマを変更してテキストデータの重複を削除します。この方法では、「多数」テーブルの狭い外部キーフィールドでカウントが発生します。

  2. または、テキストのハッシュで生成された列を作成し、ハッシュ列でGROUP BYを作成します。繰り返しますが、これはワークロードを減らすためです(狭い列インデックスをスキャンします)

編集:

元の質問は編集内容と完全には一致しませんでした。 COUNTをGROUP BYで使用すると、テーブル全体のアイテム数ではなく、グループごとのアイテム数が返されることを認識しているかどうかわかりません。

0
Chris Bednarski

このブログからの参照

以下を使用して、行カウントを見つけるためにクエリを実行できます。

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;
0
Anvesh