`

PostgreSQL服务过程中的那些事二:Pg服务进程处理简单查询六:执行器执行

阅读更多

 

       话说 查询“ select cname, comp from test1, test2 where test1.id=test2.id; 发送到服务器端, 走查询分支 exec_simple_query ,先调用 start_xact_command 初始化了事务管理相关对象和资源,接着调用 pg_parse_query ,通过 Lex Yacc 对传入 SQL 语句进行词法语法解析,生成解析树。下来调用 GetTransactionSnapshot 方法做内存快照,然后调用 pg_analyze_and_rewrite 方法,进行语义分析把 parsetree 转换成 querytree ,然后对该 querytree 进行重写。接着调用 pg_plan_queries 方法,根据 querytree 做查询 规划,生成查询计划树 plantree 。然后调用了一系列方法 CreatePortal PortalStart PortalSetResultFormat CreateDestReceiver PortalRun PortalDrop ,创建 portal 、初始化 portal 设置结果列格式、创建目的地接收者、运行portal执行查询并返回结果,然后释放 portal 相关资源,再调用 finish_xact_command 释放事务相关资源。这个例子终于执行完了。

 

1

下面是执行 plantree 的调用序列图。


 

 

执行 plantree 的调用序列图

 

上图红色方框中显示了执行 plantree 的过程,主要分为 portal 创建和初始化( CreatePortal PortalStart )、执行( PortalRun )、释放资源( PortalDrop )三个部分。 portal 是个抽象概念,它表示一个正在运行或可运行 query 的执行状态。 Portal 支持 SQL 层的 CURSOR 和协议层的 portal 。从上图中可以看出,在各个部分, portal 调用了执行器 executor 的对应方法 Executor Start Executor Run Executor Drop 完成了相关操作。

简单描述一下执行过程,方法 CreatePortal 在内存上下文 PortalMemory 里创建 portal ,并在 portal 管理器 "Portal hash" 中注册(参见《 PostgreSQL 服务过程中的那些事一:启动 postgres 服务进程一 . 七:初始化 portal 管理环境》);调用 PortalDefineQuery 为新建的 portal 设置 sourceText (就是例子里的源 SQL 语句)、 stmts (就是上一节讨论的 plantree 列表)等字段,将 portal 状态设置为 PORTAL_DEFINED ;再调用 PortalStart 初始化 portal ,在该例子里选择 PORTAL_ONE_SELECT 策略,调用 CreateQueryDesc 方法,为 portal 创建查询描述符,将 portal 状态设置为 PORTAL_READY ;调用方法 PortalRun ,根据选择策略调用相应方法,根据 portal 相关由 plantree 转化来的各节点结构由下至上逐层进行处理,涉及扫描数据、进行投射、结果缓存等;最后调用 PortalDrop 释放 portal 相关资源。

portal 有多个执行策略,依赖于执行什么样的 query (其实就是根据不同的 SQL 语句调用不同的方法以完成相应操作)。(注意:在所有情况下,一个 portal 仅执行一个源 SQL query ,并且从用户的视点,仅产生一个结果。但是,规则重写器可以扩展一个源 query 0 或多个实际的 query 。)下面是 portal 的四种策略

PORTAL_ONE_SELECT :这个 portal 包含一个 SELECT 查询。我们增加运行一个执行器作为被要求的结果。这个策略还支持可持有的 cursor (为了事务结束后访问结果,执行器结果可以被转储到一个 tuplestore 里)。

         PORTAL_ONE_RETURNING :这个 portal 包含一个伴有 RETURNING 子句的 INSERT/UPDATE/DELETE 查询(由规则重写器重写增加的可能的辅助查询 /query )。在第一次执行时,我们运行 portal 以完成和转储主 query 的结果到 portal tuplestore 里;然后这个结果按要求返回给用户。(我们不支持 query 的部分遍历悬挂,因为 AFTER 触发器代码不能处理,并且还因为我们不想在执行所有辅助 query 时冒失败风险。)

         PORTAL_ONE_MOD_WITH portal 包含一个 SELECT qiery ,但它包含数据修改 CTE 。这个目前和处理 PORTAL_ONE_RETURNING 的情况一样,因为需要触发触发器的可能性。将来处理这种情况的行为可以更像 PORTAL_ONE_SELECT

         PORTAL_UTIL_SELECT portal 包含一个 utility 语句,其返回一个象 SELECT 那样的结果(例如, WXPLAIN 或者 SHOW )。在第一次执行时,我们运行这个语句任何转储其结果到 portal tuplestore 里;然后这个结果按要求的返回给客户端。

         PORTAL_MULTI_QUERY :所有其它情况。这儿,我们不支持 portal 执行: portal query 会被运行以完成第一次调用。

 

下面是 portal 和其执行状态、策略的类型定义及执行器状态结构定义,其他涉及到节点结构定义略去。

typedef enum PortalStrategy

{

    PORTAL_ONE_SELECT ,

    PORTAL_ONE_RETURNING ,

    PORTAL_ONE_MOD_WITH ,

    PORTAL_UTIL_SELECT ,

    PORTAL_MULTI_QUERY

} PortalStrategy ;

 

typedef enum PortalStatus

{

    PORTAL_NEW ,                 /* freshly created */

    PORTAL_DEFINED ,             /* PortalDefineQuery done */

    PORTAL_READY ,            /* PortalStart complete, can run it */

    PORTAL_ACTIVE ,              /* portal is running (can't delete it) */

    PORTAL_DONE ,             /* portal is finished (don't re-run it) */

    PORTAL_FAILED             /* portal got error (can't re-run it) */

} PortalStatus ;

 

 

typedef struct PortalData * Portal ;

 

typedef struct PortalData

{

    /* Bookkeeping data */

    const char * name ;           /* portal's name */

    const char * prepStmtName ;   /* source prepared statement (NULL if none) */

    MemoryContext heap ;         /* subsidiary memory for portal */

    ResourceOwner resowner ;     /* resources owned by portal */

    void         (* cleanup ) ( Portal portal);     /* cleanup hook */

    SubTransactionId createSubid ;       /* the ID of the creating subxact */

 

    /*

      * if createSubid is InvalidSubTransactionId, the portal is held over from

      * a previous transaction

      */

 

    /* The query or queries the portal will execute */

    const char * sourceText ;     /* text of query (as of 8.4, never NULL) */

    const char * commandTag ;     /* command tag for original query */

    List        * stmts ;          /* PlannedStmts and/or utility statements */

    CachedPlan * cplan ;          /* CachedPlan, if stmts are from one */

 

    ParamListInfo portalParams ; /* params to pass to query */

 

    /* Features/options */

    PortalStrategy strategy ;    /* see above */

    int          cursorOptions ;  /* DECLARE CURSOR option bits */

 

    /* Status data */

    PortalStatus status ;        /* see above */

    bool         portalPinned ;   /* a pinned portal can't be dropped */

 

    /* If not NULL, Executor is active; call ExecutorEnd eventually: */

    QueryDesc   * queryDesc ;      /* info needed for executor invocation */

 

    /* If portal returns tuples, this is their tupdesc : */

    TupleDesc    tupDesc ;        /* descriptor for result tuples */

    /* and these are the format codes to use for the columns: */

    int16       * formats ;    /* a format code for each column */

 

    /*

      * Where we store tuples for a held cursor or a PORTAL_ONE_RETURNING or

      * PORTAL_UTIL_SELECT query.  (A cursor held past the end of its

      * transaction no longer has any active executor state.)

      */

    Tuplestorestate * holdStore ; /* store for holdable cursors */

    MemoryContext holdContext ;  /* memory containing holdStore */

 

    /*

      * atStart, atEnd and portalPos indicate the current cursor position.

      * portalPos is zero before the first row, N after fetching N'th row of

      * query.  After we run off the end, portalPos = # of rows in query, and

      * atEnd is true.  If portalPos overflows, set posOverflow (this causes us

      * to stop relying on its value for navigation).  Note that atStart

      * implies portalPos == 0, but not the reverse (portalPos could have

      * overflowed).

      */

    bool         atStart ;

    bool         atEnd ;

    bool         posOverflow ;

    long         portalPos ;

 

    /* Presentation data, primarily used by the pg_cursors system view */

    TimestampTz creation_time ;  /* time at which this portal was defined */

    bool         visible ;        /* include this portal in pg_cursors? */

}   PortalData ;

 

执行器调用的主工作状态

typedef struct EState

{

    NodeTag      type ;

 

    /* Basic state for all query types: */

    ScanDirection es_direction ; /* current scan direction */

    Snapshot     es_snapshot ;    /* time qual to use */

    Snapshot     es_crosscheck_snapshot ; /* crosscheck time qual for RI */

    List        * es_range_table ; /* List of RangeTblEntry */

    PlannedStmt * es_plannedstmt ;    /* link to top of plan tree */

 

    JunkFilter * es_junkFilter ;  /* top-level junk filter, if any */

 

    /* If query can insert/delete tuples, the command ID to mark them with */

    CommandId    es_output_cid ;

 

    /* Info about target table(s) for insert/update/delete queries: */

    ResultRelInfo * es_result_relations ; /* array of ResultRelInfos */

    int          es_num_result_relations ;        /* length of array */

    ResultRelInfo * es_result_relation_info ;     /* currently active array elt */

 

    /* Stuff used for firing triggers: */

    List        * es_trig_target_relations ;       /* trigger-only ResultRelInfos */

    TupleTableSlot * es_trig_tuple_slot ; /* for trigger output tuples */

    TupleTableSlot * es_trig_oldtup_slot ;        /* for TriggerEnabled */

 

    /* Parameter info: */

    ParamListInfo es_param_list_info ;   /* values of external params */

    ParamExecData * es_param_exec_vals ;  /* values of internal params */

 

    /* Other working state: */

    MemoryContext es_query_cxt ; /* per-query context in which EState lives */

 

    List        * es_tupleTable ;  /* List of TupleTableSlots */

 

    List        * es_rowMarks ; /* List of ExecRowMarks */

 

    uint32       es_processed ;   /* # of tuples processed */

    Oid          es_lastoid ;     /* last oid processed (by INSERT) */

 

    int          es_top_eflags ;  /* eflags passed to ExecutorStart */

    int          es_instrument ;  /* OR of InstrumentOption flags */

    bool         es_select_into ; /* true if doing SELECT INTO */

    bool         es_into_oids ;   /* true to generate OIDs in SELECT INTO */

    bool         es_finished ;    /* true when ExecutorFinish is done */

 

    List        * es_exprcontexts ; /* List of ExprContexts within EState */

 

    List        * es_subplanstates ;       /* List of PlanState for SubPlans */

 

    List        * es_auxmodifytables ;     /* List of secondary ModifyTableStates */

 

    /*

      * this ExprContext is for per-output-tuple operations, such as constraint

      * checks and index-value computations.  It will be reset for each output

      * tuple.  Note that it will be created only if needed.

      */

    ExprContext * es_per_tuple_exprcontext ;

 

    /*

      * These fields are for re-evaluating plan quals when an updated tuple is

      * substituted in READ COMMITTED mode.  es_epqTuple[] contains tuples that

      * scan plan nodes should return instead of whatever they'd normally

      * return, or NULL if nothing to return; es_epqTupleSet[] is true if a

      * particular array entry is valid; and es_epqScanDone[] is state to

      * remember if the tuple has been returned already.  Arrays are of size

      * list_length(es_range_table) and are indexed by scan node scanrelid - 1.

      */

    HeapTuple   * es_epqTuple ; /* array of EPQ substitute tuples */

    bool        * es_epqTupleSet ; /* true if EPQ tuple is provided */

    bool        * es_epqScanDone ; /* true if EPQ tuple has been fetched */

 

    /*

      * this field added at end of struct to avoid post-release ABI breakage in

      * existing release branches.  It'll be in a more logical place in 9.2.

      */

    TupleTableSlot * es_trig_newtup_slot ;        /* for TriggerEnabled */

} EState ;

 

         下面是执行这个查询的 portal 相关内存结构图:

 

 

portal 相关内存结构图

 

 

就到这儿吧。

 



------------
转载请注明出处,来自博客:
blog.csdn.net/beiigang
beigang.iteye.com

 

 





  • 大小: 190.2 KB
  • 大小: 446.1 KB
0
0
分享到:
评论

相关推荐

    postgresql--内核分析--多进程结构

    当这些代码经过编译、链接等步骤形成可执行文件,并在操作系统中运行起来后,就被赋予了一个新的身份——进程。进程不仅包含了程序的代码,还包括了数据、内存映射以及操作系统为其分配的资源等。 **进程创建**: - ...

    postgresql参数解析

    在描述中提到的`postgresql 参数注释.conf`可能是这个配置文件的一个带有注释版本,对于理解和调整参数非常有帮助。 2. **基本参数** - `data_directory`:定义了PostgreSQL数据目录的位置,存储所有数据库、日志...

    linux postgresql 安装步骤

    本文将详细介绍在Linux系统下安装和配置PostgreSQL的过程,包括卸载旧版本、手动编译安装、通过包管理器安装以及必要的配置调整。 #### 一、检查及卸载现有PostgreSQL安装 在安装新版本之前,首先要确认当前系统中...

    postgresql-12-A4_postgresql手册_

    2. 并行查询:在适当配置下,PostgreSQL 12能执行并行扫描、聚合和排序,显著提高大型查询的处理速度。 3. 增强的安全性:包括行级安全(RLS)和遮蔽(MASKING),以及认证和授权机制,确保数据安全。 综上所述,...

    MySQL和PostgreSQL的比较

    相比之下,PostgreSQL的实例启动依赖于`Postmaster`进程,通常通过`pg_ctl`命令执行。一个实例同样可以管理多个数据库,但这些数据库被组织成一个集群,存储在一个初始化时设定的磁盘区域中,该区域由一个目录构成,...

    PostgreSQL内核扩展入门.pdf

    PostgreSQL工作流程分为多个阶段,包括初始化数据库集群(bootstrap)、程序入口(main)、监听和fork(postmaster)、通信库(libpq)、事务控制进程(tcop)、解析器(parser)、重写规则(rewrite)、优化器...

    postgresql8.3

    7. **学习与使用**:PostgreSQL 8.3引入了窗口函数,允许在SQL查询中执行行级别的计算,增强了数据分析能力。同时,序列化隔离级别提升了并发事务处理的正确性,避免了死锁问题。 8. **升级与维护**:`UPGRADE.bat`...

    PostgreSQL中文手册9.1

    SQL语言函数是PostgreSQL数据库中执行查询的基本方法,手册介绍了SQL函数的基本概念和使用方法。 PL/pgSQL是PostgreSQL的过程化语言,它扩展了SQL的功能,允许创建复合数据类型,编写复杂的条件语句和循环语句。...

    如何安装postgresQL-Unix1

    4. **修改文件权限**:在安装过程中,需要将PostgreSQL源代码目录下的`configure`文件设为可执行,使用`chmod +x configure`命令完成。 5. **配置编译**:运行`sudo ./configure --prefix=/usr/local/postgres --...

    postgresql下载

    在Windows中,可以通过服务管理器来查看和控制PostgreSQL服务。此外,还需要配置环境变量,使得命令行可以识别`pg_ctl`和`psql`等命令,以便于管理和操作数据库。 在使用PostgreSQL时,我们还需要了解SQL语言,它是...

    mojo-pg:Mojolicious PostgreSQL

    `mojo-pg` 的出现使得 Mojolicious 用户能够充分利用 PostgreSQL 的强大功能,如事务处理、JSON 支持和复杂查询。 首先,让我们深入了解 `mojo-pg` 的核心特性: 1. **连接管理**:`mojo-pg` 提供了一个简单的 API...

    PostgreSQL 与 MySQL 比较

    **PostgreSQL**: PostgreSQL则通过执行`postmaster`进程(通常使用`pg_ctl`工具)启动实例。一个实例可以管理一个或多个数据库,这些数据库共同构成一个集群。集群是在磁盘上的特定区域,在安装时初始化并由一个目录...

    postgresql13-13.1.zip

    - **性能提升**:优化了查询执行器,特别是在处理大量并行操作时,提升了性能。 - **空间效率**:引入了更高效的页头压缩,减少了磁盘空间的使用。 - **索引优化**:支持更多类型的索引表达式,包括 JSONB 字段。 - ...

    PostgreSQL 并行管理实践手册

    max_parallel_workers是查询执行器从受max_parallel_workers尺寸限制的池中获取workers。max_worker_processes是workers的顶级限制后台进程的总数(此参数不允许修改,系统会自动根据实际的cpu个数(核数)来设置)...

    windows下注册和取消pg服务的命令

    如果需要检查服务是否成功启动,可以在任务管理器中找到服务对应的进程,如果配置正确,应该能看到srvany.exe正在运行,而实际的exe程序则作为srvany.exe的子进程存在。 综上所述,注册和取消Windows服务的命令是...

    在Linux和Unix系统中安装PostgreSQL

    在Linux和Unix系统中安装PostgreSQL是一个相对标准的过程,尽管具体步骤可能会因不同的发行版而异。PostgreSQL是一种开源的对象关系型数据库管理系统,它在这些操作系统中被广泛使用,提供了强大的数据存储和处理...

    postgresql-9.0 官方手册English

    - **架构**: PostgreSQL采用了客户端/服务器架构模型,其中服务器端负责数据存储和管理,而客户端用于执行SQL查询和管理数据库。 **详细解释**: 1. **安装步骤**: 在安装过程中,用户需要选择合适的版本,并按照...

    postgresql集群管理器-pgclusteradmin-阿弟@PostgreSQL1

    【PostgreSQL 集群管理器 - pgclusteradmin】是一个基于 Go 语言开发的高效能 PostgreSQL 集群管理工具,特别设计用于简化 PostgreSQL 的集群维护任务。它提供了丰富的功能,包括节点信息管理、参数配置、服务控制、...

Global site tag (gtag.js) - Google Analytics