Postgresql中常见的执行计划解释

PostgreSQL中的执行计划(或查询计划)是数据库管理系统用来详细说明如何执行特定SQL查询的一系列操作步骤。简单来说,执行计划就是数据库如何解读你的SQL语句,并决定最有效率的方式去检索或更新所需数据的蓝图。
执行计划对于性能优化至关重要,因为它可以帮助数据库管理员和开发者理解:

查询的执行路径:执行计划展示了数据库如何组织数据检索或更新的具体步骤。这包括了数据是如何从磁盘读取到内存中的,以及如何在内部处理以满足查询请求。

数据访问方法:执行计划解释了数据库是如何访问表和索引的。例如,它可能使用顺序扫描(sequential scan)、索引扫描(index scan)、位图扫描(bitmap heap scan)等不同的访问方法来检索数据。

连接方式:对于涉及多个表的查询,执行计划显示了表之间是如何连接的,比如使用嵌套循环连接(Nested Loop Join)、合并连接(Merge Join)或散列连接(Hash Join)等方法。

资源消耗估计:执行计划提供了关于查询执行需要消耗的资源(如CPU时间、I/O成本和内存使用)的估计。这有助于识别可能的性能瓶颈。

优化查询:通过分析执行计划,开发者和数据库管理员可以识别并修改低效的SQL查询,例如通过添加或调整索引、修改查询结构或更改数据库配置来提高性能。
要获取PostgreSQL中的执行计划,可以使用EXPLAIN命令,后跟你想要分析的SQL查询。例如:

EXPLAIN SELECT * FROM my_table WHERE column = 'value';

此命令将返回该查询的执行计別,但不会实际执行该查询。如果你还想看到执行该查询时的实际运行时间和资源消耗,可以使用EXPLAIN ANALYZE,这将执行查询并提供更详细的执行统计信息。
理解并有效地使用执行计划是进行数据库查询优化的关键,可以显著提高应用程序的性能和响应速度。

下面给出一下常用的执行计划分别解释一下每一步的含义:

EXPLAIN
 INSERT INTO mid_all_module_data_relation_t
   (documentCode,
    relation_id,
    mut_id,
    mr_no,
    order_code,
    rcv_sample_code,
    ssp_sample_code,
    sde_sample_code,
    su_sample_code,
    slc_sample_code,
    sp_sample_code,
    slq_sample_code,
    seq_sample_code,
    qc_sample_code,
    mut_sample_code,
    sep_level,
    remarks,
    is_valid,
    srlt_id,
    creation_date,
    created_by,
    mod_date,
    mod_by)
   SELECT concat(t1.relation_id, '-n') AS documentCode,
          t1.relation_id,
          NULL                         AS mut_id,
          t1.mr_no,
          t1.order_code,
          t1.rcv_sample_code,
          t1.ssp_sample_code,
          t1.sde_sample_code,
          t1.su_sample_code,
          t1.slc_sample_code,
          t1.sp_sample_code,
          t1.slq_sample_code,
          t1.seq_sample_code,
          t1.qc_sample_code,
          t1.mut_sample_code,
          t1.sep_level,
          t1.remarks,
          t1.is_valid,
          t1.srlt_id,
          t1.creation_date,
          t1.created_by,
          t1.mod_date,
          t1.mod_by
   FROM mid_module_data_relation_t t1
   WHERE t1.seq_sample_code IS NULL
     AND t1.mod_date >= '2024-03-01'::timestamp
     AND t1.mod_date < '2024-03-15'::timestamp
   ON CONFLICT(documentCode) DO UPDATE SET relation_id=EXCLUDED.relation_id,
                                           mr_no=EXCLUDED.mr_no,
                                           order_code=EXCLUDED.order_code,
                                           rcv_sample_code=EXCLUDED.rcv_sample_code,
                                           ssp_sample_code=EXCLUDED.ssp_sample_code,
                                           sde_sample_code=EXCLUDED.sde_sample_code,
                                           su_sample_code=EXCLUDED.su_sample_code,
                                           slc_sample_code=EXCLUDED.slc_sample_code,
                                           sp_sample_code=EXCLUDED.sp_sample_code,
                                           slq_sample_code=EXCLUDED.slq_sample_code,
                                           seq_sample_code=EXCLUDED.seq_sample_code,
                                           qc_sample_code=EXCLUDED.qc_sample_code,
                                           mut_sample_code=EXCLUDED.mut_sample_code,
                                           sep_level=EXCLUDED.sep_level,
                                           remarks=EXCLUDED.remarks,
                                           is_valid=EXCLUDED.is_valid,
                                           srlt_id=EXCLUDED.srlt_id,
                                           creation_date=EXCLUDED.creation_date,
                                           created_by=EXCLUDED.created_by,
                                           mod_date=EXCLUDED.mod_date,
                                           mod_by=EXCLUDED.mod_by;

以上代码的执行计划如下:

Insert on mid_module_data_relation_t  (cost=2407.66..470127.47 rows=0 width=0)
  ->  Nested Loop Anti Join  (cost=2407.66..470127.47 rows=24766 width=1128)
        ->  Bitmap Heap Scan on pdw_sep_data_relation_t t  (cost=2407.10..374737.61 rows=36046 width=232)
              Recheck Cond: ((edit_time >= '2024-03-01 00:00:00'::timestamp without time zone) AND (edit_time < '2024-03-15 00:00:00'::timestamp without time zone))
              Filter: ((mr_no IS NOT NULL) AND (isleaf = 1))
              ->  Bitmap Index Scan on idx_pdw_sep_data_relation_t_edit_time  (cost=0.00..2398.09 rows=121366 width=0)
                    Index Cond: ((edit_time >= '2024-03-01 00:00:00'::timestamp without time zone) AND (edit_time < '2024-03-15 00:00:00'::timestamp without time zone))
        ->  Index Only Scan using idx_mid_module_data_relation_t_srlt_id on mid_module_data_relation_t td  (cost=0.56..2.62 rows=1 width=32)
              Index Cond: (srlt_id = (t.srlt_id)::text)


这个执行计划用于描述一个插入操作(Insert)在mid_module_data_relation_t表中的执行过程。这个查询涉及一个嵌套循环反连接(Nested Loop Anti Join),它是在两个表之间进行的,即pdw_sep_data_relation_t表和mid_module_data_relation_t表。下面是对每个步骤的解释:


Insert on mid_module_data_relation_t (cost=2407.66..470127.47 rows=0 width=0): 
这表示我们正在对mid_module_data_relation_t表执行一个插入操作。成本(cost)估计从2407.66到470127.47,预计影响的行数为0(在执行计划的这个层面,并不直接插入行,因此行数为0),每行宽度为0(因为是插入操作,所以这里的宽度不适用)。

Nested Loop Anti Join (cost=2407.66..470127.47 rows=24766 width=1128): 
这个操作是一个嵌套循环反连接,预计成本从2407.66到470127.47,预计返回24766行,每行宽度为1128字节。反连接是一种特殊的连接,它返回左表中没有匹配右表的所有行。简单来说,它查找左表中不存在于右表的记录。

Bitmap Heap Scan on pdw_sep_data_relation_t t (cost=2407.10..374737.61 rows=36046 width=232):
这表示对pdw_sep_data_relation_t表进行了位图堆扫描。扫描条件是edit_time字段的值在2024-03-01 00:00:00和2024-03-15 00:00:00之间。还有一个过滤条件,即mr_no字段不能为NULL,且isleaf字段的值必须为1。预计成本从2407.10到374737.61,预计找到36046行,每行宽度为232字节。

Bitmap Index Scan on idx_pdw_sep_data_relation_t_edit_time: 
这是位图堆扫描的一部分,使用idx_pdw_sep_data_relation_t_edit_time索引来找到符合时间条件的记录。这个索引扫描的条件与上述相同。


Index Only Scan using idx_mid_module_data_relation_t_srlt_id on mid_module_data_relation_t td (cost=0.56..2.62 rows=1 width=32): 
这表示对mid_module_data_relation_t表进行了仅索引扫描,使用了idx_mid_module_data_relation_t_srlt_id索引。扫描条件是mid_module_data_relation_t表的srlt_id字段的值必须等于pdw_sep_data_relation_t表的srlt_id字段的值。预计成本从0.56到2.62,预计每次匹配到1行,每行宽度为32字节。
总的来说,这个执行计划说明了一个插入操作是如何通过在pdw_sep_data_relation_t表中找到符合条件的记录,然后通过反连接确保这些记录在mid_module_data_relation_t表中不存在,最后将这些不存在的记录插入到mid_module_data_relation_t表中。这种方式确保了插入的是pdw_sep_data_relation_t表中新的或更新的记录,而不是已经存在于mid_module_data_relation_t表中的记录。


来看另一个执行计划:

Insert on mid_all_module_data_relation_t  (cost=13716.38..578123.61 rows=0 width=0)
  Conflict Resolution: UPDATE
  Conflict Arbiter Indexes: pk_mid_all_module_data_relation_t
  ->  Nested Loop Anti Join  (cost=13716.38..578123.61 rows=724094 width=500)
        ->  Bitmap Heap Scan on mid_module_data_relation_t t1  (cost=13715.82..102420.00 rows=803018 width=280)
              Recheck Cond: (seq_sample_code IS NOT NULL)
              ->  Bitmap Index Scan on idx_mid_module_data_relation_t_seq_sample_code  (cost=0.00..13515.07 rows=803018 width=0)
                    Index Cond: (seq_sample_code IS NOT NULL)
        ->  Index Only Scan using idx_mgmt_new_sample_code on mid_gene_mutation_t t2  (cost=0.56..3.23 rows=125 width=16)
              Index Cond: (sample_code = (t1.seq_sample_code)::text)


这个执行计划描述了对mid_all_module_data_relation_t表进行的一个插入操作,其中涉及冲突解决策略和两个表mid_module_data_relation_t和mid_gene_mutation_t的关联查询。下面是详细解释:

基本操作
Insert on mid_all_module_data_relation_t (cost=13716.38..578123.61 rows=0 width=0): 
这说明是一个对mid_all_module_data_relation_t表的插入操作。成本估计(cost)从13716.38到578123.61,预计影响的行数为0(在生成执行计划时,不会计算实际插入的行数),每行宽度为0(因为是插入操作,所以没有宽度概念)。

冲突解决
Conflict Resolution: UPDATE: 
如果插入操作遇到唯一键(通常是主键)冲突,将会执行更新操作替代插入。
Conflict Arbiter Indexes: pk_mid_all_module_data_relation_t: 
冲突解决策略使用的是pk_mid_all_module_data_relation_t索引,这意味着如果有记录的主键已经存在于mid_all_module_data_relation_t表中,则会触发更新操作而非插入新记录。

查询细节
Nested Loop Anti Join (cost=13716.38..578123.61 rows=724094 width=500): 
这是一个嵌套循环反连接操作,用于在两个表之间进行关联查询,并确保左表(mid_module_data_relation_t)中的记录在右表(mid_gene_mutation_t)中不存在。预计会处理724094行数据,每行宽度为500字节。

左表扫描
Bitmap Heap Scan on mid_module_data_relation_t t1 (cost=13715.82..102420.00 rows=803018 width=280): 
这个步骤展示了对mid_module_data_relation_t表的位图堆扫描,条件是seq_sample_code字段非空。这表明查询正在搜索有seq_sample_code值的所有记录。预计找到803018行,每行宽度为280字节。
Bitmap Index Scan on idx_mid_module_data_relation_t_seq_sample_code: 这是位图堆扫描的一部分,使用idx_mid_module_data_relation_t_seq_sample_code索引来快速定位满足条件的记录。

右表扫描
Index Only Scan using idx_mgmt_new_sample_code on mid_gene_mutation_t t2 (cost=0.56..3.23 rows=125 width=16): 
这个步骤描述了对mid_gene_mutation_t表的仅索引扫描,使用idx_mgmt_new_sample_code索引。条件是sample_code字段的值必须与左表mid_module_data_relation_t中的seq_sample_code字段相匹配。预计每次匹配到125行,每行宽度为16字节。

总结
整个执行计划描述了一个通过关联mid_module_data_relation_t和mid_gene_mutation_t两表,尝试向mid_all_module_data_relation_t表插入数据的过程。如果插入的数据在mid_all_module_data_relation_t表中已经存在(基于pk_mid_all_module_data_relation_t索引判断),则执行更新操作。查询主要通过seq_sample_code字段在两个表之间建立关联,并利用索引来优化数据检索和冲突检测。

平时写完代码后可以简单的查看一下执行计划,看看哪里可能会存在性能瓶颈;遇到复杂的语句跑不动,通过执行计划分析下会有好的优化方法。

相关推荐

  1. Postgresql常见执行计划解释

    2024-03-25 04:52:01       22 阅读
  2. Mysql执行计划怎么分析?

    2024-03-25 04:52:01       19 阅读
  3. Shell执行.sh文件常见方式

    2024-03-25 04:52:01       8 阅读
  4. Oracle执行计划字段后(+)意思

    2024-03-25 04:52:01       29 阅读
  5. PG DBA培训23:PostgreSQL执行计划与统计信息

    2024-03-25 04:52:01       33 阅读
  6. 【MySQL】MySQL执行计划

    2024-03-25 04:52:01       37 阅读
  7. 一些常见PostgreSQL问题和答案

    2024-03-25 04:52:01       17 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-25 04:52:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-25 04:52:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-25 04:52:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-25 04:52:01       20 阅读

热门阅读

  1. vue3模板引用介绍

    2024-03-25 04:52:01       21 阅读
  2. 数据结构面试常见问题

    2024-03-25 04:52:01       19 阅读
  3. Day 30回溯06

    2024-03-25 04:52:01       21 阅读
  4. flink的MaxOutOfOrderness 和 Allowedlateness 区别

    2024-03-25 04:52:01       20 阅读
  5. 【Swift】如何让实例对象像函数一样使用

    2024-03-25 04:52:01       21 阅读
  6. ftp协议的彻底研究

    2024-03-25 04:52:01       17 阅读
  7. c++和c语言的区别实例

    2024-03-25 04:52:01       18 阅读
  8. 再次度过我的创作纪念日

    2024-03-25 04:52:01       15 阅读
  9. MySQL索引介绍

    2024-03-25 04:52:01       18 阅读
  10. Qt笔记 事件分发

    2024-03-25 04:52:01       18 阅读
  11. Qt:使用ctrl+z快捷键取消文本框修改

    2024-03-25 04:52:01       16 阅读
  12. Android Selinux详解[七]--如何给可执行程序bin加标签

    2024-03-25 04:52:01       15 阅读