よく理解され、多くの議論がなされている理由により、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_statistic
にANALYZE
によって格納される情報の量、特に各列の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
は非常に便利に見えるので、心の奥底に置いていただければ幸いです。私たちのシステムの多くの場合に役立つと思うので、一般的にターゲットを少し上げたいと思います。
まず、備考:クエリは次のように簡単に記述できます。
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
してみてください。これにより、新しくTRUNCATE
dテーブルの結果も修正されます。 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はこの領域で何の改善ももたらしません。