postgresql plancache --doing

c 复制代码
/*
 * CachedPlanSource(更恰当的名称应为 CachedQuery) 表示预期会多次使用的 SQL 查询。它存储:
 *   - 查询源文本
 *   - 原始解析树
 *   - 经过分析和重写后的查询树
 *   - 以及相关附加数据
 * 
 * 当查询依赖的对象发生 DDL 变更时,缓存可能失效。 此时会丢弃已分析和重写的查询树,并在下次需要时重建。
 * CachedPlan 表示从 CachedPlanSource 派生的实际执行计划。
 * 计划分为两种类型:
 *   - 通用计划(generic):适用于任意参数集
 *   - 自定义计划(custom):针对特定参数集优化
 * plancache.c 包含决策逻辑,决定具体执行时采用哪种计划。 若使用通用缓存计划,它可跨多次执行重复使用, 因此调用方必须始终将 CachedPlan
 * 视为只读。
 *
 * 成功构建并"保存"后,CachedPlanSource 通常与后端进程生命周期一致,但也可显式删除。
 * CachedPlan 采用引用计数机制,当最后一个引用被释放时自动销毁。 注意:CachedPlan 可能比其来源的 CachedPlanSource 存活更久。
 *
 * "未保存"的 CachedPlanSource 可用于生成计划,但:
 *   - 驻留在临时存储中
 *   - 不会响应系统失效(sinval)事件更新
 *
 * 内存管理规则:
 *   - saved CachedPlanSource 创建的 CachedPlan存在于类似永久存储中,其引用必须由永久数据结构或 ResourceOwner 持有(避免内存泄漏)
 *   - unsaved CachedPlanSource 创建的 CachedPlan 位于调用方内存上下文的子空间中,其引用生命周期不应超过该上下文
 *   (引用计数在此场景多为形式要求,但若需提前丢弃计划仍有用)
 *
 * CachedPlanSource 有两个关联的内存上下文:一个保存存储结构体本身、查询源文本和原始解析树,另一个保存重写后的查询树及相关数据
 * 这种设计使得查询树失效时可轻松丢弃。
 *
 * 针对一次性查询的特殊处理: 支持"oneshot"模式,该模式:
 *     - 不进行数据复制或失效检查
 *     - 无独立内存上下文,所有数据存于调用方 CurrentMemoryContext
 *     - 只能通过清除整个上下文释放内存
 *   oneshot 计划始终视为未保存。
 *
 * 注意:
 *   commandTag 引用的字符串不属于附属存储; 它被假定为编译时常量字符串。
 *   与 portals 类似,commandTag 为 NULL 当且仅当原始查询字符串(重写前)为空字符串。
 */
typedef struct CachedPlanSource
{
	int			magic;			/* should equal CACHEDPLANSOURCE_MAGIC */
	struct RawStmt *raw_parse_tree; /* output of raw_parser(), or NULL */
	struct Query *analyzed_parse_tree;	/* analyzed parse tree, or NULL */
	const char *query_string;	//query 原文本
	CommandTag	commandTag;		/* command tag for query */
	Oid		   *param_types;	/* array of parameter type OIDs, or NULL */
	int			num_params;		/* length of param_types array */
	ParserSetupHook parserSetup;	/* alternative parameter spec method */
	void	   *parserSetupArg;
	PostRewriteHook postRewrite;	/* see SetPostRewriteHook */
	void	   *postRewriteArg;
	int			cursor_options; /* cursor options used for planning */
	bool		fixed_result;	/* disallow change in result tupdesc? */
	TupleDesc	resultDesc;		/* result type; NULL = doesn't return tuples */
	MemoryContext context;		//上下文1,保存存储结构体本身、查询源文本和原始解析树,保存以上字段内存
	//以下字段为查询重写相关
	List	   *query_list;		/* list of Query nodes, or NIL if not valid */
	List	   *relationOids;	/* OIDs of relations the queries depend on */
	List	   *invalItems;		/* other dependencies, as PlanInvalItems */
	struct SearchPathMatcher *search_path;	/* search_path used for parsing
											 * and planning */
	MemoryContext query_context;	//上下文2 保存重写后的查询树及相关数据,以上字段
	Oid			rewriteRoleId;	/* Role ID we did rewriting for */
	bool		rewriteRowSecurity; /* row_security used during rewrite */
	bool		dependsOnRLS;	/* is rewritten query specific to the above? */
	/* If we have a generic plan, this is a reference-counted link to it: */
	struct CachedPlan *gplan;	/* generic plan, or NULL if not valid */
	/* Some state flags: */
	bool		is_oneshot;		/* is it a "oneshot" plan? */
	bool		is_complete;	/* has CompleteCachedPlan been done? */
	bool		is_saved;		/* has CachedPlanSource been "saved"? */
	bool		is_valid;		/* is the query_list currently valid? */
	int			generation;		/* increments each time we create a plan */
	/* If CachedPlanSource has been saved, it is a member of a global list */
	dlist_node	node;			/* list link, if is_saved */
	/* State kept to help decide whether to use custom or generic plans: */
	double		generic_cost;	/* cost of generic plan, or -1 if not known */
	double		total_custom_cost;	/* total cost of custom plans so far */
	int64		num_custom_plans;	/* # of custom plans included in total */
	int64		num_generic_plans;	/* # of generic plans */
} CachedPlanSource;
c 复制代码
//CachedPlan 表示源自 CachedPlanSource 的执行计划。引用计数包含来自父级 CachedPlanSource 的链接(如有)以及任何活跃的计划执行,因此
//当引用计数归零时,该计划可被安全丢弃。结构体本身及其附属数据均存储在由 context 字段指定的上下文中。这种设计使得释放不再需要的缓存计划变
//得简单。(但若 is_oneshot 为 true,则上下文不完全属于 CachedPlan,因此无法执行释放操作。)
typedef struct CachedPlan
{
	int			magic;			/* should equal CACHEDPLAN_MAGIC */
	List	   *stmt_list;		/* list of PlannedStmts */
	bool		is_oneshot;		/* is it a "oneshot" plan? */
	bool		is_saved;		/* is CachedPlan in a long-lived context? */
	bool		is_valid;		/* is the stmt_list currently valid? */
	Oid			planRoleId;		/* Role ID the plan was created for */
	bool		dependsOnRole;	/* is plan specific to that role? */
	TransactionId saved_xmin;	/* if valid, replan when TransactionXmin changes from this value */
	int			generation;		/* parent's generation number for this plan */
	int			refcount;		/* count of live references to this struct */
	MemoryContext context;		/* context containing this CachedPlan */
} CachedPlan;

plansource 实际存储在双向链表中,正常只有pbe协议发起的sql,以及存储过程中会使用到plansource ,或者手动使用prepare语句会创建plansource ,psql连接的sql使用不到plansource

c 复制代码
/*
 * This is the head of the backend's list of "saved" CachedPlanSources (i.e.,
 * those that are in long-lived storage and are examined for sinval events).
 * We use a dlist instead of separate List cells so that we can guarantee
 * to save a CachedPlanSource without error.
 */
static dlist_head saved_plan_list = DLIST_STATIC_INIT(saved_plan_list);

/*
 * This is the head of the backend's list of CachedExpressions.
 */
static dlist_head cached_expression_list = DLIST_STATIC_INIT(cached_expression_list);

注册失效消息的回调函数

c 复制代码
PostgresMain
	RelationCacheInitialize
	InitCatalogCache
	InitPlanCache
InitPlanCache(void)
{
	//plan 依赖的表结构,procoid,typeoid改变时,失效plancache
	CacheRegisterRelcacheCallback(PlanCacheRelCallback, (Datum) 0);
	CacheRegisterSyscacheCallback(PROCOID, PlanCacheObjectCallback, (Datum) 0);
	CacheRegisterSyscacheCallback(TYPEOID, PlanCacheObjectCallback, (Datum) 0);
	//以下数据改变时,失效所有计划
	CacheRegisterSyscacheCallback(NAMESPACEOID, PlanCacheSysCallback, (Datum) 0);
	CacheRegisterSyscacheCallback(OPEROID, PlanCacheSysCallback, (Datum) 0);
	CacheRegisterSyscacheCallback(AMOPOPID, PlanCacheSysCallback, (Datum) 0);
	CacheRegisterSyscacheCallback(FOREIGNSERVEROID, PlanCacheSysCallback, (Datum) 0);
	CacheRegisterSyscacheCallback(FOREIGNDATAWRAPPEROID, PlanCacheSysCallback, (Datum) 0);
}
相关推荐
future14124 小时前
freeRTOS学习日记
1024程序员节
刘新明19894 小时前
算法还原案例4-OLLVM_MD5
开发语言·前端·javascript·1024程序员节
布朗克1684 小时前
MySQL 运算符详细说明
数据库·mysql·运算符·1024程序员节
Dream_言十4 小时前
光通信|高效动态的自由空间-光纤CVB通信
学习·论文笔记·1024程序员节
诚实可靠王大锤4 小时前
react-native实现多列表左右滑动+滚动TabBar悬停
javascript·react native·react.js·1024程序员节
Cherry Zack4 小时前
FastAPI 入门指南 :基础概念与核心特性
开发语言·python·fastapi·1024程序员节
<但凡.4 小时前
Linux修炼:基础IO(二)
linux·运维·服务器·1024程序员节
2301_803554525 小时前
std::unique_lockstd::mutex lock(mtx) 深度详解
1024程序员节
黑翼杰克斯5 小时前
关于buildroot文件系统中rootfs的内容,该怎么增删(瑞芯微rv1126b)
linux·音视频·1024程序员节