大きなテーブルでの行のカウントは、PostgreSQL では遅いことが知られています。MVCCモデルでは、正確な数を得るためにライブ行の完全なカウントが必要です。あなたの場合のようにカウントが正確である必要がない場合、これを劇的にスピードアップするための回避策があります。
(「正確な」カウントでさえ、同時書き込み負荷の下では到着時に無効になる可能性があることに注意してください。)
正確な数
大きなテーブルでは遅い。
同時書き込み操作では、取得した瞬間に古くなっている可能性があります。
SELECT count(*) AS exact_count FROM myschema.mytable;
見積もり
非常に高速:
SELECT reltuples AS estimate FROM pg_class where relname = 'mytable';
通常、見積もりは非常に近いです。どのくらい近いかは、十分に実行されているかどうかによって異なりますANALYZE。VACUUM「十分」は、テーブルへの書き込みアクティビティのレベルによって定義されます。
より安全な見積もり
上記は、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';
へのキャストは、特に大きなカウントの場合にbigint、数値を適切にフォーマットします。real
より良い見積もり
SELECT reltuples::bigint AS estimate
FROM pg_class
WHERE oid = 'myschema.mytable'::regclass;
より速く、よりシンプルに、より安全に、よりエレガントに。Object Identifier Typesのマニュアルを参照してください。
Postgres 9.4 以降では、無効なテーブル名の例外の代わりに何も取得しないように'myschema.mytable'::regclass置き換えます。to_regclass('myschema.mytable')見る:
より正確な見積もり (追加費用はほとんどかかりません)
Postgres プランナーと同じことができます。マニュアルの行推定例の引用:
これらの数値は、前回VACUUMまたはANALYZE表の時点で最新のものです。その後、プランナーはテーブル内の実際の現在のページ数をフェッチします (これは安価な操作であり、テーブル スキャンを必要としません)。それが異なる場合は、relpagesそれreltuplesに応じてスケーリングされ、現在の行数の見積もりに到達します。
Postgres はestimate_rel_sizeで定義されたものを使用します。これは、リレーションがバキュームされていないため、 にsrc/backend/utils/adt/plancat.cデータがないというまれなケースもカバーします。pg_classSQL でも同様のことができます。
最小限の形
SELECT (reltuples / relpages * (pg_relation_size(oid) / 8192))::bigint
FROM pg_class
WHERE oid = 'mytable'::regclass; -- your table here
安全かつ明示的
SELECT (CASE WHEN c.reltuples < 0 THEN NULL -- never vacuumed
WHEN c.relpages = 0 THEN float8 '0' -- empty table
ELSE c.reltuples / c.relpages END
* (pg_relation_size(c.oid) / pg_catalog.current_setting('block_size')::int)
)::bigint
FROM pg_class c
WHERE c.oid = 'myschema.mytable'::regclass; -- schema-qualified table here
空のテーブルや見たことのないテーブルVACUUMやANALYZE. のマニュアルpg_class:
テーブルがまだバキュームまたは分析されていない場合、行数が不明であることを示すがreltuples含まれます。-1
このクエリが を返す場合は、テーブルに対してまたはをNULL実行して繰り返します。(別の方法として、Postgres のように列の型に基づいて行の幅を見積もることもできますが、これは面倒でエラーが発生しやすくなります。)ANALYZEVACUUM
このクエリが を返す0場合、テーブルは空です。しかし、私はANALYZE確認したいと思います。(そして、おそらくautovacuum設定を確認してください。)
通常block_sizeは 8192current_setting('block_size')::intです。まれな例外をカバーします。
テーブルとスキーマの修飾により、すべてsearch_pathの範囲とスコープの影響を受けなくなります。
いずれにせよ、クエリは一貫して < 0.1 ミリ秒かかります。
その他の Web リソース:
SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);
@a_horseのコメントのように、コマンドに追加された句は、何らかの理由で統計が十分に最新でないSELECT場合に役立ちます。pg_class例えば:
autovacuum走っていません。
INSERT大きな/ UPDATE/の直後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