PG実行計画分析

1.Explainの基本的な使用法

1.1コマンドの説明

explain [ ( option [,...] ) ] statement
explain [ analyze ] [ verbose ] statement

option选项有:
analyze [ boolean ]                     //会实际执行SQL,并返回SQL实际执行的相关统计信息
verbose [ boolean ]                     //显示执行计划的附加信息
costs [ boolean ]                       //默认开启,显示每个计划节点的启动成本、总成本,预计返回行数,预估返回结果集每行平均宽度
buffers [ boolean ]                     //显示缓冲区使用信息
format [ text | xml | json | yaml ]     //执行计划执行输出格式

1.2結果出力の解釈を説明する

実行計画の例:

db1=# explain (analyze 1,verbose 1,costs 1,buffers 1) select * from t3 where name='aa';
                                             QUERY PLAN
----------------------------------------------------------------------------------------------------
 Seq Scan on public.t3  (cost=0.00..1.10 rows=1 width=70) (actual time=0.007..0.008 rows=2 loops=1)
   Output: id, name, gmt_create
   Filter: ((t3.name)::text = 'aa'::text)
   Rows Removed by Filter: 6
   Buffers: shared hit=1
 Planning Time: 0.139 ms
 Execution Time: 0.020 ms
(7 rows)

結果出力の説明:

 Seq Scan on public.t3                      //seq scan表示全表扫描
 (cost=0.00..1.10 rows=1 width=70)          //以".."为分隔符,前面表示启动的成本,后面表示返回结果集第一行记录的成功,rows表示预估结果集行数,width表示预估结果集每行的宽度
 (actual time=0.007..0.008 rows=2 loops=1)  //当analyze设置为true时,会输出SQL实际执行后的相关资源消耗信息,分别时启动时间,返回结果集花费时间,返回结果集行数
 Output: id, name, gmt_create               //当verbose为true时,输出查询字段
 Filter: ((t3.name)::text = 'aa'::text)     //过滤条件
 Buffers: shared hit=1                      //当buffers为true时,输出缓冲区命中代价,共读取共享内存中的一个数据块,
 Planning Time: 0.139 ms
 Execution Time: 0.020 ms

2.スキャンデータ方式

2.1全表スキャン

全表スキャンも順次スキャンになり、実行プランの「SeqScan」で識別されます。全表スキャンでは、表のすべてのデータブロックを最初から最後まで順番に読み取ります。

db1=# explain (analyze 1,verbose 1,costs 1,buffers 1) select * from t3 where name='ff';
                                               QUERY PLAN
---------------------------------------------------------------------------------------------------------
 Seq Scan on public.t3  (cost=0.00..18.30 rows=225 width=15) (actual time=0.011..0.117 rows=225 loops=1)
   Output: id, name, gmt_create
   Filter: ((t3.name)::text = 'ff'::text)
   Rows Removed by Filter: 759
   Buffers: shared hit=6
 Planning Time: 0.057 ms
 Execution Time: 0.137 ms
(7 rows)

2.2インデックススキャン

インデックススキャンは、データのクエリの効率を上げるように設計されており、実行プランで「$ {index_name}を使用したインデックススキャン」とマークされています。インデックスは、最初にインデックスをスキャンしてレコードの物理的な場所を見つけ、次にバックテーブルの必須フィールドにクエリを実行します。

db1=# explain (analyze 1,verbose 1,costs 1,buffers 1) select * from t3 where name='ww';
                                                       QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
 Index Scan using idx_t3_name on public.t3  (cost=0.28..8.29 rows=1 width=15) (actual time=0.043..0.043 rows=0 loops=1)
   Output: id, name, gmt_create
   Index Cond: ((t3.name)::text = 'ww'::text)
   Buffers: shared hit=1 read=1
 Planning Time: 0.065 ms
 Execution Time: 0.056 ms
(6 rows)

2.3ビットマップスキャン

ビットマップインデックスはインデックス作成の方法でもあり、実行プランの「ビットマップヒープスキャン」で識別されます。インデックスをスキャンし、条件に一致する行またはブロックのビットマップをメモリに作成し、インデックスがスキャンされた後、ビットマップからテーブルにデータファイルから対応するデータを読み取ります。2つのインデックスを残している場合は、実際の状況に応じてインデックスをビットマップに形成し、「or」と「and」の計算を実行してビットマップにマージし、テーブルのデータファイルのデータを読み取ることができます。

db1=# explain (analyze 1,verbose 1,costs 1,buffers 1) select * from t3 where name='gg';
                                                       QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on public.t3  (cost=5.27..12.89 rows=129 width=15) (actual time=0.048..0.064 rows=129 loops=1)
   Output: id, name, gmt_create
   Recheck Cond: ((t3.name)::text = 'gg'::text)
   Heap Blocks: exact=6
   Buffers: shared hit=7 read=1
   ->  Bitmap Index Scan on idx_t3_name  (cost=0.00..5.24 rows=129 width=0) (actual time=0.042..0.042 rows=129 loops=1)
         Index Cond: ((t3.name)::text = 'gg'::text)
         Buffers: shared hit=1 read=1
 Planning Time: 0.059 ms
 Execution Time: 0.085 ms
(10 rows)

2.4条件フィルタリング

スキャンした結果セットを条件でフィルタリングする必要がある場合、実行プランで「Filter :(条件)」とマークされます。インデックスをフィルタリングするかどうかは、特定の状況によって異なります。

db1=# explain (analyze 1,verbose 1,costs 1,buffers 1) select * from t3 where name='ww' and gmt_create<now();
                                                       QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
 Index Scan using idx_t3_name on public.t3  (cost=0.28..8.30 rows=1 width=15) (actual time=0.013..0.013 rows=0 loops=1)
   Output: id, name, gmt_create
   Index Cond: ((t3.name)::text = 'ww'::text)
   Filter: (t3.gmt_create < now())
   Buffers: shared hit=2
 Planning Time: 0.080 ms
 Execution Time: 0.024 ms
(7 rows)

3、テーブル関連付け方法

3.1NestLoop参加

ネストされたループでは、外部テーブルが内部テーブルを駆動し、条件を満たす外部テーブルレコードに対して、内部テーブルで関連付けマッチングが1つずつ実行されます。ネストされた検査の場合、外部テーブルはできるだけ小さくする必要があり、内部テーブルのテーブル関連フィールドには有効なインデックスがあることが保証されている必要があります。

db1=# explain select * from t3 join t4 on t3.name=t4.name where t4.name='ww';
                                 QUERY PLAN
-----------------------------------------------------------------------------
 Nested Loop  (cost=0.28..17.40 rows=1 width=30)
   ->  Index Scan using idx_t3_name on t3  (cost=0.28..8.29 rows=1 width=15)
         Index Cond: ((name)::text = 'ww'::text)
   ->  Seq Scan on t4  (cost=0.00..9.10 rows=1 width=15)
         Filter: ((name)::text = 'ww'::text)
(5 rows)

3.2ハッシュ結合

テーブルアソシエーションで小さいテーブルを選択し、メモリ内のテーブルアソシエーションフィールドのハッシュテーブルを作成してから、大きいテーブルをスキャンしてハッシュ検出ハッシュテーブルを実行し、ハッシュテーブルに一致するレコードを見つけます。テーブルが比較的小さい場合は、すべての小さなテーブルを直接メモリに入れることができます。メモリを置くことができない場合、オプティマイザはそれをいくつかの異なるパーティションに分割し、メモリに入れることができない部分をに書き込みます。ディスクの一時セグメント。IOパフォーマンスを最大化するには、より大きな一時セグメントが必要です。

db1=# explain select * from t3 join t4 on t3.name=t4.name where t4.id>300;
                            QUERY PLAN
------------------------------------------------------------------
 Hash Join  (cost=28.14..360.84 rows=27026 width=30)
   Hash Cond: ((t4.name)::text = (t3.name)::text)
   ->  Seq Scan on t4  (cost=0.00..9.10 rows=188 width=15)
         Filter: (id > 300)
   ->  Hash  (cost=15.84..15.84 rows=984 width=15)
         ->  Seq Scan on t3  (cost=0.00..15.84 rows=984 width=15)
(6 rows)

3.3マージ結合

通常の状況では、ハッシュ結合の効果はマージ結合よりも優れています。ソースデータにインデックスがある場合、または結果が並べ替えられている場合、並べ替えマージ結合を実行するときに並べ替える必要はありません。この場合、効果マージ結合の方が優れています。ハッシュ結合の場合。

db2=# explain select * from t1 join t2 on t1.id=t2.id;
                                QUERY PLAN
---------------------------------------------------------------------------
 Merge Join  (cost=4.60..9.07 rows=80 width=14)
   Merge Cond: (t1.id = t2.id)
   ->  Index Scan using t1_pkey on t1  (cost=0.28..34.74 rows=898 width=7)
   ->  Sort  (cost=4.33..4.53 rows=80 width=7)
         Sort Key: t2.id
         ->  Seq Scan on t2  (cost=0.00..1.80 rows=80 width=7)
(6 rows)

おすすめ

転載: blog.csdn.net/weixin_37692493/article/details/109232501