大きなテーブルの行をカウントすることは、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(*)パフォーマンス専用の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のマニュアルを参照してください。
to_regclass('myschema.mytable')
Postgres 9.4以降で使用して、無効なテーブル名の例外を回避します。
SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);
@a_horseがコメントしたように、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