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;
より速く、よりシンプルに、より安全に、よりエレガントに。オブジェクト識別子の種類に関するマニュアルを参照してください。
'myschema.mytable'::regclass
を置き換えます to_regclass('myschema.mytable')
を使用 Postgres 9.4以降では、無効なテーブル名の例外の代わりに何も取得しません。参照:
- 特定のスキーマにテーブルが存在するかどうかを確認する方法
さらに良い見積もり(追加コストはごくわずかです)
Postgresプランナーが行うことを実行できます。 行推定の例の引用 マニュアルの内容:
これらの番号は、最後の
VACUUM
の時点で最新のものです。 またはANALYZE
テーブルの上。次に、プランナはテーブル内の実際の現在のページ数をフェッチします(これは安価な操作であり、テーブルスキャンを必要としません)。それがrelpages
と異なる場合 次にreltuples
それに応じてスケーリングされ、現在の行数の見積もりに到達します。
Postgresはestimate_rel_size
を使用します src/backend/utils/adt/plancat.c
で定義されています 、pg_class
にデータがない場合のコーナーケースもカバーしています 関係が決して真空にされなかったので。 SQLでも同様のことができます:
最小形式
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
を返す場合 、ANALYZE
を実行します またはVACUUM
テーブルのために繰り返します。 (または、Postgresのように列タイプに基づいて行幅を見積もることもできますが、これは面倒でエラーが発生しやすくなります。)
このクエリが0
を返す場合 、テーブルが空のようです。しかし、私はANALYZE
確かめる。 (そして多分あなたのautovacuum
をチェックしてください 設定。)
通常、block_size
は8192です。current_setting('block_size')::int
まれな例外をカバーしています。
テーブルとスキーマの資格により、search_path
の影響を受けなくなります。 とスコープ。
いずれにせよ、クエリは一貫して<0.1ミリ秒かかります。
その他のWebリソース:
- Postgres Wiki FAQ
- カウントの見積もりとcount(*)のパフォーマンスに関するPostgreswikiページ
TABLESAMPLE SYSTEM (n)
Postgres9.5以降
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
からの見積もり より速く、より正確になります。
実際の質問への回答
まず、totalcountが事前定義された定数よりも大きい場合は、そのテーブルの行数を知る必要があります。
そしてそれかどうか...
...カウントが私の定数値を通過した瞬間に可能であり、カウントを停止します(そして、行カウントが大きいことを通知するためにカウントが終了するのを待たないでください)。
はい。 LIMIT
でサブクエリを使用できます :
SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;
Postgres実際にはカウントを停止します 指定された制限を超えると、正確で最新のが得られます 最大nまでカウント 行(例では500000)、および n そうでなければ。 pg_class
の見積もりほど速くはありません 、しかし。