166

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

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

一定値を超えたらすぐにカウントを止めることはできますか?

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

このようなもの:

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

7 に答える 7

356

大きなテーブルでの行のカウントは、PostgreSQL では遅いことが知られています。MVCCモデルでは、正確な数を得るためにライブ行の完全なカウントが必要です。あなたの場合のようにカウントが正確である必要がない場合、これを劇的にスピードアップするための回避策があります。

(「正確な」カウントでさえ、同時書き込み負荷の下では到着時に無効になる可能性があることに注意してください。)

正確な数

大きなテーブルでは遅い。
同時書き込み操作では、取得した瞬間に古くなっている可能性があります。

SELECT count(*) AS exact_count FROM myschema.mytable;
見積もり

非常に高速:

SELECT reltuples AS estimate FROM pg_class where relname = 'mytable';

通常、見積もりは非常に近いです。どのくらい近いかは、十分に実行されているかどうかによって異なりますANALYZEVACUUM「十分」は、テーブルへの書き込みアクティビティのレベルによって定義されます。

より安全な見積もり

上記は、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

空のテーブルや見たことのないテーブルVACUUMANALYZE. のマニュアルpg_class:

テーブルがまだバキュームまたは分析されていない場合、行数が不明であることを示すがreltuples含まれます。-1

このクエリが を返す場合は、テーブルに対してまたはをNULL実行して繰り返します。(別の方法として、Postgres のように列の型に基づいて行の幅を見積もることもできますが、これは面倒でエラーが発生しやすくなります。)ANALYZEVACUUM

このクエリが を返す0場合、テーブルは空です。しかし、私はANALYZE確認したいと思います。(そして、おそらくautovacuum設定を確認してください。)

通常block_sizeは 8192current_setting('block_size')::intです。まれな例外をカバーします。

テーブルとスキーマの修飾により、すべてsearch_pathの範囲とスコープの影響を受けなくなります。

いずれにせよ、クエリは一貫して < 0.1 ミリ秒かかります。

その他の Web リソース:


TABLESAMPLE SYSTEM (n)Postgres 9.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​​方が高速で正確です。

実際の質問への回答

まず、そのテーブルの行数を知る必要があります。合計数が定義済みの定数よりも大きい場合は、

そしてそれは...

...カウントが定数値を通過した瞬間に可能であり、カウントを停止します(カウントが終了して行カウントが大きいことを通知するのを待ちません)。

はい。次のサブクエリをLIMIT使用できます。

SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;

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

于 2011-10-30T13:47:32.453 に答える
11

私は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 がある程度の妥当な誤差範囲内で返される行数を予測できるほど単純なクエリであれば、うまくいくかもしれません。

于 2011-10-30T04:19:02.323 に答える
0

テキスト列の幅は?

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

私はお勧めします:

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

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

編集:

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

于 2011-10-30T05:28:20.433 に答える
0

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

SELECT (case when cnt > 500000 then 500000 else cnt end) myCnt
FROM (SELECT count(*) cnt FROM table WHERE rownum<=500001)
于 2011-10-30T04:11:28.037 に答える
-4

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 は順序付けられたテーブル (クラスター化インデックス) です。

ここでは、さらに高速な (しかし信頼性の低い) メソッドについて詳しく説明します。

于 2014-10-29T08:45:56.483 に答える