web-dev-qa-db-ja.com

Postgresでの個別の値の見積もりの​​改善

よく理解され、多くの議論がなされている理由により、Postgresでのフルカウントは遅くなる可能性があります。そのため、可能な場合は、代わりに推定手法を使用しています。行の場合、pg_statsは問題ないようです。ビューの場合、EXPLAINによって返される推定値を抽出しても問題ありません。

https://www.cybertec-postgresql.com/en/count-made-fast/

しかし、明確な値はどうですか?ここでは、運がはるかに少なくなっています。見積もりが100%正しい場合もあれば、2倍または20倍ずれている場合もあります。特に、切り捨てられたテーブルの見積もりはひどく古くなっているようです(?)。

このテストを実行したところ、いくつかの結果が得られました。

analyze Assembly_prods; -- Doing an ANLYZE to give pg_stats every help.

select 'count(*) distinct' as method,
        count(*) as count
from (select distinct Assembly_id 
      from Assembly_prods) d 
union all
select 'n_distinct from pg_stats' as method,
        n_distinct as count
from pg_stats 
where tablename  = 'Assembly_prods' and
      attname    = 'Assembly_id';

結果:

method                      count
count(*) distinct           28088
n_distinct from pg_stats    13805

それは2倍だけずれていますが、私のデータでははるかに悪いようです。見積もりを使わないところまで。他に試すことができるものはありますか?これはPG12が改善するものですか?

ファローアップ

1日の時間数が非常に多いため、これまでSET STATISTICSを実験したことはありませんでした。ローレンツの答えに触発されて、私は簡単に見てみました。ドキュメントからの有用なコメントは次のとおりです。

https://www.postgresql.org/docs/current/planner-stats.html

pg_statisticANALYZEによって格納される情報の量、特に各列のmost_common_valsおよびhistogram_bounds配列のエントリの最大数は、列ごとに設定できます。 ALTER TABLE SET STATISTICSコマンドを使用するか、グローバルにdefault_statistics_target構成変数を設定します。デフォルトの制限は現在100エントリです。制限を引き上げると、特にデータ分布が不規則な列の場合、pg_statisticでより多くのスペースを消費し、見積もりの​​計算に少し時間がかかるという犠牲を払って、より正確なプランナー見積もりを行うことができます。逆に、単純なデータ分布の列には下限で十分な場合があります。

私はしばしば、いくつかの一般的な値と多くのまれな値を持つテーブルを持っています。またはその逆なので、適切なしきい値は異なります。 SET STATISTICSを使用したことがない場合は、サンプリングレートを目標エントリ数として設定できます。デフォルトは100であるため、1000の方が忠実度が高くなります。これは次のようになります。

ALTER TABLE Assembly_prods 
    ALTER COLUMN Assembly_id
    SET STATISTICS 1000;

テーブルまたはインデックスでSET STATISTICSを使用できます。インデックスに関する興味深い記事は次のとおりです。

https://akorotkov.github.io/blog/2017/05/31/alter-index-weird/

現在のドキュメントはインデックスにSET STATISTICSをリストしていることに注意してください

そこで、1、10、100、1000、および10,000のしきい値を試し、467,767行と28,088の異なる値を持つテーブルからこれらの結果を取得しました。

Target   Estimate  Difference  Missing
     1   13,657    14,431      51%
    10   13,867    14,221      51%
   100   13,759    14,329      51%
 1,000   24,746     3,342      12%
10,000   28,088         0       0%

明らかに、1つのケースから一般的な結論を引き出すことはできませんが、SET STATISTICSは非常に便利に見えるので、心の奥底に置いていただければ幸いです。私たちのシステムの多くの場合に役立つと思うので、一般的にターゲットを少し上げたいと思います。

1
Morris de Oryx

まず、備考:クエリは次のように簡単に記述できます。

SELECT count(DISTINCT Assembly_id) FROM Assembly_prods;

また、n_distictも負になる可能性があるため、統計クエリが間違っています。クエリする必要があります:

SELECT CASE WHEN s.n_distinct < 0
            THEN - s.n_distinct * t.reltuples
            ELSE s.n_distinct
       END AS n_distinct
FROM pg_class t
   JOIN pg_namespace n ON n.oid = t.relnamespace
   JOIN pg_stats s ON t.relname = s.tablename
                      AND n.nspname = s.schemaname
WHERE s.schemaname = 'public'
  AND s.tablename = 'Assembly_prods'
  AND s.attname = 'Assembly_id';

そのような単純なクエリの場合、統計には適切な見積もりが含まれている必要があります。

見積もりがずれている場合は、テーブルをANALYZEしてみてください。これにより、新しくTRUNCATEdテーブルの結果も修正されます。 TRUNCATEによってPostgreSQLがテーブルを自動分析することはありません(ここでは改善の余地があるかもしれません)。

それで結果が改善される場合は、構成することでテーブルがより頻繁に分析されることを確認してください

ALTER TABLE Assembly_prods SET (autovacuum_analyze_scale_factor = 0.05);

autovacuum_analyze_scale_factorを0に設定し、autovacuum_analyze_thresholdをテーブルの毎日の変更率に上げることもできます。

ANALYZEだけでは推定が改善されない場合は、サンプルのサイズを増やします。

ALTER TABLE Assembly_prods ALTER Assembly_id SET STATISTICS 1000;

新しいANALYZEは、より適切な見積もりを生成するはずです。

より複雑なクエリに対して適切なn_distinct見積もりを取得することは、ますます困難になります。時々 拡張統計 は見積もりをかなり改善します。

私の知る限り、PostgreSQLv12はこの領域で何の改善ももたらしません。

1
Laurenz Albe