PostgreSQL在何处处理 sql查询之三十三

本文涉及的产品
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
简介:

接前面,在 PortalStart 中调用了 ExecutorStart,ExecutorStart 会调用 InitPlan:

复制代码
/* ----------------------------------------------------------------
 *        InitPlan
 *
 *        Initializes the query plan: open files, allocate storage
 *        and start up the rule manager
 * ----------------------------------------------------------------
 */
static void
InitPlan(QueryDesc *queryDesc, int eflags)
{
    CmdType        operation = queryDesc->operation;
    PlannedStmt *plannedstmt = queryDesc->plannedstmt;
    Plan       *plan = plannedstmt->planTree;
    List       *rangeTable = plannedstmt->rtable;
    EState       *estate = queryDesc->estate;
    PlanState  *planstate;
    TupleDesc    tupType;
    ListCell   *l;
    int            i;

    /*
     * Do permissions checks
     */
    ExecCheckRTPerms(rangeTable, true);

    /*
     * initialize the node's execution state
     */
    estate->es_range_table = rangeTable;
    estate->es_plannedstmt = plannedstmt;

    /*
     * initialize result relation stuff, and open/lock the result rels.
     *
     * We must do this before initializing the plan tree, else we might try to
     * do a lock upgrade if a result rel is also a source rel.
     */
    if (plannedstmt->resultRelations)
    {
        List       *resultRelations = plannedstmt->resultRelations;
        int            numResultRelations = list_length(resultRelations);
        ResultRelInfo *resultRelInfos;
        ResultRelInfo *resultRelInfo;

        resultRelInfos = (ResultRelInfo *)
            palloc(numResultRelations * sizeof(ResultRelInfo));
        resultRelInfo = resultRelInfos;
        foreach(l, resultRelations)
        {
            Index        resultRelationIndex = lfirst_int(l);
            Oid            resultRelationOid;
            Relation    resultRelation;

            resultRelationOid = getrelid(resultRelationIndex, rangeTable);
            resultRelation = heap_open(resultRelationOid, RowExclusiveLock);
            InitResultRelInfo(resultRelInfo,
                              resultRelation,
                              resultRelationIndex,
                              estate->es_instrument);
            resultRelInfo++;
        }
        estate->es_result_relations = resultRelInfos;
        estate->es_num_result_relations = numResultRelations;
        /* es_result_relation_info is NULL except when within ModifyTable */
        estate->es_result_relation_info = NULL;
    }
    else
    {
        /*
         * if no result relation, then set state appropriately
         */
        estate->es_result_relations = NULL;
        estate->es_num_result_relations = 0;
        estate->es_result_relation_info = NULL;
    }

    /*
     * Similarly, we have to lock relations selected FOR UPDATE/FOR SHARE
     * before we initialize the plan tree, else we'd be risking lock upgrades.
     * While we are at it, build the ExecRowMark list.
     */
    estate->es_rowMarks = NIL;
    foreach(l, plannedstmt->rowMarks)
    {
        PlanRowMark *rc = (PlanRowMark *) lfirst(l);
        Oid            relid;
        Relation    relation;
        ExecRowMark *erm;

        /* ignore "parent" rowmarks; they are irrelevant at runtime */
        if (rc->isParent)
            continue;

        switch (rc->markType)
        {
            case ROW_MARK_EXCLUSIVE:
            case ROW_MARK_SHARE:
                relid = getrelid(rc->rti, rangeTable);
                relation = heap_open(relid, RowShareLock);
                break;
            case ROW_MARK_REFERENCE:
                relid = getrelid(rc->rti, rangeTable);
                relation = heap_open(relid, AccessShareLock);
                break;
            case ROW_MARK_COPY:
                /* there's no real table here ... */
                relation = NULL;
                break;
            default:
                elog(ERROR, "unrecognized markType: %d", rc->markType);
                relation = NULL;    /* keep compiler quiet */
                break;
        }

        /* Check that relation is a legal target for marking */
        if (relation)
            CheckValidRowMarkRel(relation, rc->markType);

        erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
        erm->relation = relation;
        erm->rti = rc->rti;
        erm->prti = rc->prti;
        erm->rowmarkId = rc->rowmarkId;
        erm->markType = rc->markType;
        erm->noWait = rc->noWait;
        ItemPointerSetInvalid(&(erm->curCtid));
        estate->es_rowMarks = lappend(estate->es_rowMarks, erm);
    }

    /*
     * Initialize the executor's tuple table to empty.
     */
    estate->es_tupleTable = NIL;
    estate->es_trig_tuple_slot = NULL;
    estate->es_trig_oldtup_slot = NULL;
    estate->es_trig_newtup_slot = NULL;

    /* mark EvalPlanQual not active */
    estate->es_epqTuple = NULL;
    estate->es_epqTupleSet = NULL;
    estate->es_epqScanDone = NULL;

    /*
     * Initialize private state information for each SubPlan.  We must do this
     * before running ExecInitNode on the main query tree, since
     * ExecInitSubPlan expects to be able to find these entries.
     */
    Assert(estate->es_subplanstates == NIL);
    i = 1;                        /* subplan indices count from 1 */
    foreach(l, plannedstmt->subplans)
    {
        Plan       *subplan = (Plan *) lfirst(l);
        PlanState  *subplanstate;
        int            sp_eflags;

        /*
         * A subplan will never need to do BACKWARD scan nor MARK/RESTORE. If
         * it is a parameterless subplan (not initplan), we suggest that it be
         * prepared to handle REWIND efficiently; otherwise there is no need.
         */
        sp_eflags = eflags & EXEC_FLAG_EXPLAIN_ONLY;
        if (bms_is_member(i, plannedstmt->rewindPlanIDs))
            sp_eflags |= EXEC_FLAG_REWIND;

        subplanstate = ExecInitNode(subplan, estate, sp_eflags);

        estate->es_subplanstates = lappend(estate->es_subplanstates,
                                           subplanstate);

        i++;
    }

    /*
     * Initialize the private state information for all the nodes in the query
     * tree.  This opens files, allocates storage and leaves us ready to start
     * processing tuples.
     */
    planstate = ExecInitNode(plan, estate, eflags);

    /*
     * Get the tuple descriptor describing the type of tuples to return.
     */
    tupType = ExecGetResultType(planstate);

    /*
     * Initialize the junk filter if needed.  SELECT queries need a filter if
     * there are any junk attrs in the top-level tlist.
     */
    if (operation == CMD_SELECT)
    {
        bool        junk_filter_needed = false;
        ListCell   *tlist;

        foreach(tlist, plan->targetlist)
        {
            TargetEntry *tle = (TargetEntry *) lfirst(tlist);

            if (tle->resjunk)
            {
                junk_filter_needed = true;
                break;
            }
        }

        if (junk_filter_needed)
        {
            JunkFilter *j;

            j = ExecInitJunkFilter(planstate->plan->targetlist,
                                   tupType->tdhasoid,
                                   ExecInitExtraTupleSlot(estate));
            estate->es_junkFilter = j;

            /* Want to return the cleaned tuple type */
            tupType = j->jf_cleanTupType;
        }
    }

    queryDesc->tupDesc = tupType;
    queryDesc->planstate = planstate;
}
复制代码

先从 tupDesc 来入手吧:

复制代码
/*
 * This struct is passed around within the backend to describe the structure
 * of tuples.  For tuples coming from on-disk relations, the information is
 * collected from the pg_attribute, pg_attrdef, and pg_constraint catalogs.
 * Transient row types (such as the result of a join query) have anonymous
 * TupleDesc structs that generally omit any constraint info; therefore the
 * structure is designed to let the constraints be omitted efficiently.
 *
 * Note that only user attributes, not system attributes, are mentioned in
 * TupleDesc; with the exception that tdhasoid indicates if OID is present.
 *
 * If the tupdesc is known to correspond to a named rowtype (such as a table's
 * rowtype) then tdtypeid identifies that type and tdtypmod is -1.    Otherwise
 * tdtypeid is RECORDOID, and tdtypmod can be either -1 for a fully anonymous
 * row type, or a value >= 0 to allow the rowtype to be looked up in the
 * typcache.c type cache.
 *
 * Tuple descriptors that live in caches (relcache or typcache, at present)
 * are reference-counted: they can be deleted when their reference count goes
 * to zero.  Tuple descriptors created by the executor need no reference
 * counting, however: they are simply created in the appropriate memory
 * context and go away when the context is freed.  We set the tdrefcount
 * field of such a descriptor to -1, while reference-counted descriptors
 * always have tdrefcount >= 0.
 */
typedef struct tupleDesc
{
    int            natts;            /* number of attributes in the tuple */
    Form_pg_attribute *attrs;
    /* attrs[N] is a pointer to the description of Attribute Number N+1 */
    TupleConstr *constr;        /* constraints, or NULL if none */
    Oid            tdtypeid;        /* composite type ID for tuple type */
    int32        tdtypmod;        /* typmod for tuple type */
    bool        tdhasoid;        /* tuple has oid attribute in its header */
    int            tdrefcount;        /* reference count, or -1 if not counting */
}    *TupleDesc;
复制代码

对InitPlan进行简化和进一步分析:

复制代码
static void
InitPlan(QueryDesc *queryDesc, int eflags)
{
    ...

    /*
     * initialize result relation stuff, and open/lock the result rels.
     *
     * We must do this before initializing the plan tree, else we might try to
     * do a lock upgrade if a result rel is also a source rel.
     */
    if (plannedstmt->resultRelations)
    {
        ...
    }
    else
    {
        /*
         * if no result relation, then set state appropriately
         */
        estate->es_result_relations = NULL;
        estate->es_num_result_relations = 0;
        estate->es_result_relation_info = NULL;
    }

    ...
    queryDesc->tupDesc = tupType;
    queryDesc->planstate = planstate;
}
复制代码

实际测试后发现 select * from tst01 这样的SQL文,

得到的 (plannedstmt->resultRelations) 判断值为false。

然后,在  foreach(l, plannedstmt->rowMarks) 之前加点判断:

    l= list_head(plannedstmt->rowMarks);

    if (l != NULL)
        fprintf(stderr, "l is not null\n");
    else
        fprintf(stderr,"l is null\n");

发现,l 是空值。

复制代码
/* ----------------------------------------------------------------
 *        InitPlan
 *
 *        Initializes the query plan: open files, allocate storage
 *        and start up the rule manager
 * ----------------------------------------------------------------
 */
static void
InitPlan(QueryDesc *queryDesc, int eflags)
{
    ...
    if (plannedstmt->resultRelations)
    {
       ...
    }
    else
    {
        /*
         * if no result relation, then set state appropriately
         */
        estate->es_result_relations = NULL;
        estate->es_num_result_relations = 0;
        estate->es_result_relation_info = NULL;
    }

    /*
     * Similarly, we have to lock relations selected FOR UPDATE/FOR SHARE
     * before we initialize the plan tree, else we'd be risking lock upgrades.
     * While we are at it, build the ExecRowMark list.
     */
    estate->es_rowMarks = NIL;
    foreach(l, plannedstmt->rowMarks)
    {
       ...
    }

    /*
     * Initialize the executor's tuple table to empty.
     */
    estate->es_tupleTable = NIL;
    estate->es_trig_tuple_slot = NULL;
    estate->es_trig_oldtup_slot = NULL;
    estate->es_trig_newtup_slot = NULL;

    /* mark EvalPlanQual not active */
    estate->es_epqTuple = NULL;
    estate->es_epqTupleSet = NULL;
    estate->es_epqScanDone = NULL;

    ...
}
复制代码

接着往下分析:

发现运行 select * from test01 where id<10 这样的sql文的时候,

foreach(l, plannedstmt->subplans) 也一次没有得到执行。

复制代码
static void
InitPlan(QueryDesc *queryDesc, int eflags)
{
    ...
    if (plannedstmt->resultRelations)
    {
       ...
    }
    else
    {
        /*
         * if no result relation, then set state appropriately
         */
        estate->es_result_relations = NULL;
        estate->es_num_result_relations = 0;
        estate->es_result_relation_info = NULL;
    }

    ...
    foreach(l, plannedstmt->rowMarks)
    {
       ...
    }

    /*
     * Initialize the executor's tuple table to empty.
     */
    estate->es_tupleTable = NIL;
    estate->es_trig_tuple_slot = NULL;
    estate->es_trig_oldtup_slot = NULL;
    estate->es_trig_newtup_slot = NULL;

    /* mark EvalPlanQual not active */
    estate->es_epqTuple = NULL;
    estate->es_epqTupleSet = NULL;
    estate->es_epqScanDone = NULL;

    ...

    i = 1;                        /* subplan indices count from 1 */
    foreach(l, plannedstmt->subplans)
    {
       ...
    }

    /*
     * Initialize the private state information for all the nodes in the query
     * tree.  This opens files, allocates storage and leaves us ready to start
     * processing tuples.
     */
    planstate = ExecInitNode(plan, estate, eflags);

    /*
     * Get the tuple descriptor describing the type of tuples to return.
     */
    tupType = ExecGetResultType(planstate);

    ...
}
复制代码

接下来看 tupType到底是什么,也就是表的记录的属性信息。

复制代码
typedef struct tupleDesc
{
    int            natts;            /* number of attributes in the tuple */
    Form_pg_attribute *attrs;
    /* attrs[N] is a pointer to the description of Attribute Number N+1 */
    TupleConstr *constr;        /* constraints, or NULL if none */
    Oid            tdtypeid;        /* composite type ID for tuple type */
    int32        tdtypmod;        /* typmod for tuple type */
    bool        tdhasoid;        /* tuple has oid attribute in its header */
    int            tdrefcount;        /* reference count, or -1 if not counting */
}    *TupleDesc;
复制代码

重新整理一下:

复制代码
static void
InitPlan(QueryDesc *queryDesc, int eflags)
{
    ...
    if (plannedstmt->resultRelations)
    {
       ...
    }
    else
    {
        estate->es_result_relations = NULL;
        estate->es_num_result_relations = 0;
        estate->es_result_relation_info = NULL;
    }
    ...

/*
     * Initialize the private state information for all the nodes in the query
     * tree.  This opens files, allocates storage and leaves us ready to start
     * processing tuples.
     */
    planstate = ExecInitNode(plan, estate, eflags);

    /*
     * Get the tuple descriptor describing the type of tuples to return.
     */
    tupType = ExecGetResultType(planstate);

    /*
     * Initialize the junk filter if needed.  SELECT queries need a filter if
     * there are any junk attrs in the top-level tlist.
     */
    if (operation == CMD_SELECT)
    {
bool        junk_filter_needed = false;
        ListCell   *tlist;

        foreach(tlist, plan->targetlist)
        {
            fprintf(stderr,"In foreach (tlist, plan->targetlist) \n");

            TargetEntry *tle = (TargetEntry *) lfirst(tlist);

            if (tle->resjunk)
            {
                junk_filter_needed = true;
                break;
            }
        }
        ...
    }

    queryDesc->tupDesc = tupType;
    queryDesc->planstate = planstate;
}
复制代码

有趣的事情来了:这一段,

如果我 select id from tst04; for 循环执行一次

如果我 select id,val from tst04; for 循环执行二次。

也就是说 plan->targelist 的长度,就是 select 列表里字段的个数。

复制代码
 foreach(tlist, plan->targetlist)
        {
            fprintf(stderr,"In foreach (tlist, plan->targetlist) \n");

            TargetEntry *tle = (TargetEntry *) lfirst(tlist);

            if (tle->resjunk)
            {
                junk_filter_needed = true;
                break;
            }
        }
复制代码

 事实上,这个在  调用 InitPlan之前,就已经准备好了:

Plan       *plan = plannedstmt->planTree;









本文转自健哥的数据花园博客园博客,原文链接:http://www.cnblogs.com/gaojian/archive/2013/05/30/3106372.html,如需转载请自行联系原作者
相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
1天前
|
SQL NoSQL Java
Java使用sql查询mongodb
通过使用 MongoDB Connector for BI 和 JDBC,开发者可以在 Java 中使用 SQL 语法查询 MongoDB 数据库。这种方法对于熟悉 SQL 的团队非常有帮助,能够快速实现对 MongoDB 数据的操作。同时,也需要注意到这种方法的性能和功能限制,根据具体应用场景进行选择和优化。
23 9
|
22天前
|
SQL 存储 人工智能
Vanna:开源 AI 检索生成框架,自动生成精确的 SQL 查询
Vanna 是一个开源的 Python RAG(Retrieval-Augmented Generation)框架,能够基于大型语言模型(LLMs)为数据库生成精确的 SQL 查询。Vanna 支持多种 LLMs、向量数据库和 SQL 数据库,提供高准确性查询,同时确保数据库内容安全私密,不外泄。
92 7
Vanna:开源 AI 检索生成框架,自动生成精确的 SQL 查询
|
29天前
|
SQL Java
使用java在未知表字段情况下通过sql查询信息
使用java在未知表字段情况下通过sql查询信息
36 8
|
1月前
|
SQL 安全 PHP
PHP开发中防止SQL注入的方法,包括使用参数化查询、对用户输入进行过滤和验证、使用安全的框架和库等,旨在帮助开发者有效应对SQL注入这一常见安全威胁,保障应用安全
本文深入探讨了PHP开发中防止SQL注入的方法,包括使用参数化查询、对用户输入进行过滤和验证、使用安全的框架和库等,旨在帮助开发者有效应对SQL注入这一常见安全威胁,保障应用安全。
59 4
|
1月前
|
SQL 监控 关系型数据库
SQL语句当前及历史信息查询-performance schema的使用
本文介绍了如何使用MySQL的Performance Schema来获取SQL语句的当前和历史执行信息。Performance Schema默认在MySQL 8.0中启用,可以通过查询相关表来获取详细的SQL执行信息,包括当前执行的SQL、历史执行记录和统计汇总信息,从而快速定位和解决性能瓶颈。
|
1月前
|
SQL 存储 缓存
如何优化SQL查询性能?
【10月更文挑战第28天】如何优化SQL查询性能?
151 10
|
1月前
|
SQL 关系型数据库 MySQL
|
1月前
|
SQL 关系型数据库 数据库
PostgreSQL性能飙升的秘密:这几个调优技巧让你的数据库查询速度翻倍!
【10月更文挑战第25天】本文介绍了几种有效提升 PostgreSQL 数据库查询效率的方法,包括索引优化、查询优化、配置优化和硬件优化。通过合理设计索引、编写高效 SQL 查询、调整配置参数和选择合适硬件,可以显著提高数据库性能。
366 1
|
2月前
|
SQL 数据库 开发者
功能发布-自定义SQL查询
本期主要为大家介绍ClkLog九月上线的新功能-自定义SQL查询。
|
1月前
|
SQL 关系型数据库 MySQL
mysql编写sql脚本:要求表没有主键,但是想查询没有相同值的时候才进行插入
mysql编写sql脚本:要求表没有主键,但是想查询没有相同值的时候才进行插入
35 0