要約: GaussDB (DWS) の運用および保守ソリューションを 2 つのシナリオ例を通じて説明します。
この記事は、ファーウェイ クラウド コミュニティ「GaussDB (DWS) Operation and Maintenance -- Common Scenarios and Solutions for Inaccurate Estimation of Base Table Statistical Information」(著者: Ge Li Ge) から共有されたものです。
シナリオ 1: ベース テーブルがフィールドの暗黙的な型をフィルター処理する場合、ベース テーブルの推定行数が小さすぎます
これらのシナリオのほとんどは DWS で対応できますが、暗黙的な型変換の結果が統計情報におけるフィールド列挙値の表現と異なる場合、推定に重大な誤差が生じます。
元のSQLは次のとおりです
SELECT * FROM dmgrpdi.dwl_inv_res_rpt_ci_grp_f WHERE period_id=202212 AND source_flag=1;
対応する実行計画
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
id | operation | E-rows | E-memory | E-width | E-costs
----+------------------------------------------------------------------+--------+----------+---------+-----------
1 | -> Row Adapter | 14160 | | 717 | 680025.43
2 | -> Vector Streaming (type: GATHER) | 14160 | | 717 | 680025.43
3 | -> Vector Partition Iterator | 14160 | 1MB | 717 | 678241.33
4 | -> Partitioned CStore Scan on dwl_inv_res_rpt_ci_grp_f | 14160 | 1MB | 717 | 678241.33
Predicate Information (identified by plan id)
-------------------------------------------------------------------------------
3 --Vector Partition Iterator
Iterations: 1
4 --Partitioned CStore Scan on dwl_inv_res_rpt_ci_grp_f
Filter: ((period_id = 202212::numeric) AND ((source_flag)::bigint = 1))
Pushdown Predicate Filter: (period_id = 202212::numeric)
Partitions Selected by Static Prune: 36
source_flag フィールドに暗黙的な型変換があることが判明しました。source_flag フィールドの統計をクエリします。
postgres=# SELECT most_common_vals,most_common_freqs, histogram_bounds FROM pg_stats WHERE tablename = 'dwl_inv_res_rpt_ci_grp_f' AND attname = 'source_flag';
most_common_vals | most_common_freqs | histogram_bounds
------------------+-----------------------------------+------------------
{01,02,04,03} | {.440034,.241349,.217413,.101089} | {05,06}
(1 row)
暗黙的な型変換の結果(1)が統計上のフィールド列挙値('01')の表現と異なることが判明
解決策: フィルター条件を変更し、型変換を禁止し、正しい定数値を使用してフィルター条件を書き込みます。
上記のSQL文のsource_flag=1はsource_flag='01'に変更され、変更後のSQL文は以下のようになります。
SELECT * FROM dmgrpdi.dwl_inv_res_rpt_ci_grp_f WHERE period_id=202212 AND source_flag='01';
新しいステートメントの実行計画をクエリします。
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------
id | operation | E-rows | E-memory | E-width | E-costs
----+------------------------------------------------------------------+-----------+----------+---------+-----------
1 | -> Row Adapter | 108359075 | | 717 | 480542.98
2 | -> Vector Streaming (type: GATHER) | 108359075 | | 717 | 480542.98
3 | -> Vector Partition Iterator | 108359075 | 1MB | 717 | 478758.88
4 | -> Partitioned CStore Scan on dwl_inv_res_rpt_ci_grp_f | 108359075 | 1MB | 717 | 478758.88
Predicate Information (identified by plan id)
-------------------------------------------------------------------------------------------------
3 --Vector Partition Iterator
Iterations: 1
4 --Partitioned CStore Scan on dwl_inv_res_rpt_ci_grp_f
Filter: ((period_id = 202212::numeric) AND (source_flag = '01'::text))
Pushdown Predicate Filter: ((period_id = 202212::numeric) AND (source_flag = '01'::text))
Partitions Selected by Static Prune: 36
シナリオ 2: ベース テーブルが複数列の複合主キーでフィルタリングされている場合、ベース テーブルの行数が多すぎると推定されます。
このシナリオは、DWS がベース テーブル上の複数のフィルター条件間に弱い相関を採用しているためで、複数のフィルター条件が主キーである場合、結果セットが過大評価される可能性があります。
元のSQLは次のとおりです
SELECT * FROM mca.mca_period_rate_t mca_rate2
WHERE period_number = '202208' AND from_currency_code = 'RMB' AND to_currency_code = 'USD'
実行情報は以下の通りです
id | operation | A-time | A-rows | E-rows | Peak Memory | E-memory | A-width | E-width | E-costs
----+------------------------------------------------------+--------------------+--------+--------+-------------+----------+---------+---------+----------
1 | -> Row Adapter | 444.735 | 1 | 2033 | 227KB | | | 321 | 22601.41
2 | -> Vector Streaming (type: GATHER) | 444.720 | 1 | 2033 | 873KB | | | 321 | 22601.41
3 | -> CStore Scan on mca_period_rate_t mca_rate2 | [435.167, 435.167] | 1 | 2033 | [5MB, 5MB] | 1MB | | 321 | 22427.41
Predicate Information (identified by plan id)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3 --CStore Scan on mca_period_rate_t mca_rate2
Filter: (((period_number)::text = '202208'::text) AND ((from_currency_code)::text = 'RMB'::text) AND ((to_currency_code)::text = 'USD'::text))
Rows Removed by Filter: 425812
Pushdown Predicate Filter: (((period_number)::text = '202208'::text) AND ((from_currency_code)::text = 'RMB'::text) AND ((to_currency_code)::text = 'USD'::text))
ベース テーブル mca.mca_period_rate_t の行数の推定値が非常に大きすぎることがわかります。
次の SQL ステートメントを使用して、テーブル mca.mca_period_rate_t の定義を表示します。
SELECT pg_get_tabledef('mca.mca_period_rate_t'::regclass);
クエリテーブル mca.mca_period_rate_t 定義
SELECT pg_get_tabledef('mca.mca_period_rate_t');
SET search_path = mca;
CREATE TABLE mca_period_rate_t (
seq numeric NOT NULL,
period_number character varying(10) NOT NULL,
from_currency_code character varying(20) NOT NULL,
to_currency_code character varying(20) NOT NULL,
begin_rate numeric(35,18),
end_rate numeric(35,18),
avg_rate numeric(35,18),
creation_date timestamp(0) without time zone NOT NULL,
created_by numeric NOT NULL,
last_update_date timestamp(0) without time zone,
last_updated_by numeric,
rmb_begin_rate numeric(35,18),
usd_begin_rate numeric(35,18),
rmb_end_rate numeric(35,18),
usd_end_rate numeric(35,18),
rmb_avg_rate numeric(35,18),
usd_avg_rate numeric(35,18),
crt_cycle_id numeric,
crt_job_instance_id numeric,
last_upd_cycle_id numeric,
upd_job_instance_id numeric,
cdc_key_id character varying(128) DEFAULT sys_guid(),
end_rate2 numeric(35,18),
avg_rate2 numeric(35,18),
last_period_end_rate numeric(35,18)
)
WITH (orientation=column, compression=low, colversion=2.0, enable_delta=false)
DISTRIBUTE BY REPLICATION
TO GROUP group_version1;
CREATE UNIQUE INDEX mca_period_rate_u1 ON mca.mca_period_rate_t USING cbtree (period_number, from_currency_code, to_currency_code) TABLESPACE pg_default;
(period_number, from_currency_code, to_currency_code) がその組み合わせの一意のインデックスであることがわかりました。
解決策: 複合インデックス列の複数列の統計を収集する
この方式は、ベース テーブルが比較的小さい場合にのみ適用できることに注意してください。複数列の統計ではパーセンテージ サンプリングを使用して統計を計算する必要があるため、テーブルが比較的大きい場合、統計の計算に時間がかかります。
次のステートメントを実行して、上記のクエリ ステートメントの (period_number、from_currency_code、to_currency_code) 複数列の統計情報を収集します。
ANALYZE mca.mca_period_rate_t((period_number, from_currency_code, to_currency_code));
複数列の統計を収集した後、ベーステーブルの行数推定値が通常に戻る
id | operation | A-time | A-rows | E-rows | Peak Memory | A-width | E-width | E-costs
----+-------------------------------------------------------------------------------------+--------------------+--------+--------+-------------+---------+---------+---------
1 | -> Row Adapter | 195.504 | 1 | 1 | 227KB | | 321 | 675.14
2 | -> Vector Streaming (type: GATHER) | 195.491 | 1 | 1 | 873KB | | 321 | 675.14
3 | -> CStore Index Scan using mca_period_rate_u1 on mca_period_rate_t mca_rate2 | [164.344, 164.344] | 1 | 1 | [5MB, 5MB] | | 321 | 501.14
Predicate Information (identified by plan id)
----------------------------------------------------------------------------------------------------------------------------------------------------------
3 --CStore Index Scan using mca_period_rate_u1 on mca_period_rate_t mca_rate2
Index Cond: (((period_number)::text = '202208'::text) AND ((from_currency_code)::text = 'RMB'::text) AND ((to_currency_code)::text = 'USD'::text))
クリックしてフォローして、Huawei Cloudの最新テクノロジーについて初めて学びましょう~