postgreSQL中的高速缓存

news2024/12/24 4:46:31

1. 高速缓存简介

​如下图所示,当一个postgreSQL进程读取一个元组时,需要获取表的基本信息(例如:表的oid、索引信息和统计信息等)及元组的模式信息,这些信息被分别记录在多个系统表中。通常一个表的模式信息在设定好后的变化频率很低,因此在对同一个表的多个元组操作时,每次都去读取系统表的元组来构建模式信息显然是没有必要的,这也会降低元组的操作效率。为了减少对系统表的访问,在每个进程本地内存区域设置了两种cache,一种是用来存储系统表的元组,一种是用来存储表的基本信息,从而可以让进程更快的构建出表的基本信息和元组的模式信息。cache在某一个进程对系统表发生更改时其他的 backend 进程要能够感知到,需要有一套维护cache 一致性的机制,也就是 PG 的 InvalidMessage机制。

用户表是如何被管理的,参考:https://zhuanlan.zhihu.com/p/623283855

在这里插入图片描述

2. SysCache

syscache主要用来缓存最近使用过的系统表的元组。从代码实现看,syscache就是一个catcache数组,数组的长度为系统表的个数,每一个系统表唯一的对应catcache数组的一个元素。

  • catcache数据结构
typedef struct catcache
{
	int			id;				/* catcache id */
	int			cc_nbuckets;	/* # of hash buckets in this cache */
	TupleDesc	cc_tupdesc;		/* tuple descriptor (copied from reldesc) */
	dlist_head *cc_bucket;		/* hash buckets */
	CCHashFN	cc_hashfunc[CATCACHE_MAXKEYS];	/* hash function for each key */
	CCFastEqualFN cc_fastequal[CATCACHE_MAXKEYS];	/* fast equal function for
													 * each key */
	int			cc_keyno[CATCACHE_MAXKEYS]; /* AttrNumber of each key */
	dlist_head	cc_lists;		/* list of CatCList structs */
	int			cc_ntup;		/* # of tuples currently in this cache */
	int			cc_nkeys;		/* # of keys (1..CATCACHE_MAXKEYS) */
	const char *cc_relname;		/* name of relation the tuples come from */
	Oid			cc_reloid;		/* OID of relation the tuples come from */
	Oid			cc_indexoid;	/* OID of index matching cache keys */
	bool		cc_relisshared; /* is relation shared across databases? */
	slist_node	cc_next;		/* list link */
	ScanKeyData cc_skey[CATCACHE_MAXKEYS];	/* precomputed key info for heap
											 * scans */

	/*
	 * Keep these at the end, so that compiling catcache.c with CATCACHE_STATS
	 * doesn't break ABI for other modules
	 */
#ifdef CATCACHE_STATS
	long		cc_searches;	/* total # searches against this cache */
	long		cc_hits;		/* # of matches against existing entry */
	long		cc_neg_hits;	/* # of matches against negative entry */
	long		cc_newloads;	/* # of successful loads of new entry */

	/*
	 * cc_searches - (cc_hits + cc_neg_hits + cc_newloads) is number of failed
	 * searches, each of which will result in loading a negative entry
	 */
	long		cc_invals;		/* # of entries invalidated from cache */
	long		cc_lsearches;	/* total # list-searches */
	long		cc_lhits;		/* # of matches against existing lists */
#endif
} CatCache;
2.1 syscache初始化

在对postgres进程初始化时,会对syscache进行初始化,将查找系统表元组的关键信息写入到catcache数组的元素中。

涉及到的数据结构如下:

  • cacheinfo:存储所有系统表的catcache描述信息

    struct cachedesc
    {
    	Oid			reloid;			/* OID of the relation being cached */
    	Oid			indoid;			/* OID of index relation for this cache */
    	int			reloidattr;		/* attr number of rel OID reference, or 0 */
    	int			nkeys;			/* # of keys needed for cache lookup */
    	int			key[4];			/* attribute numbers of key attrs */
    	int			nbuckets;		/* number of hash buckets for this cache */
    };
    
    static const struct cachedesc cacheinfo[] = {
    	{AggregateRelationId,		/* AGGFNOID */
    		AggregateFnoidIndexId,
    		1,
    		{
    			Anum_pg_aggregate_aggfnoid,
    			0,
    			0,
    			0
    		},
    		16
    	},
    	...
    	
    }
    
  • catcacheheader:catcache使用cc_next字段构成一个单向链表,头部使用此结构体记录

    typedef struct catcacheheader
    {
    	slist_head	ch_caches;		/* head of list of CatCache structs */
    	int			ch_ntup;		/* # of tuples in all caches */
    } CatCacheHeader;
    

初始化阶段1:使用cacheinfo初始化catcache数组

typedef struct catcache
{
	...
	TupleDesc	cc_tupdesc;		/* tuple descriptor (copied from reldesc) */
	int			cc_nbuckets;	/* # of hash buckets in this cache */
	dlist_head *cc_bucket;		/* hash buckets */
	int			cc_keyno[CATCACHE_MAXKEYS]; /* AttrNumber of each key */
	int			cc_nkeys;		/* # of keys (1..CATCACHE_MAXKEYS) */
	Oid			cc_reloid;		/* OID of relation the tuples come from */
	Oid			cc_indexoid;	/* OID of index matching cache keys */
	...
}

初始化阶段2:根据对应的系统表填充catcache中元组描述信息(cc_tupdesc)、系统表名(cc_relname)和查找关键字的相关字段

typedef struct catcache
{
	...
	CCHashFN	cc_hashfunc[CATCACHE_MAXKEYS];	/* hash function for each key */
	CCFastEqualFN cc_fastequal[CATCACHE_MAXKEYS];	/* fast equal function for each key */
	const char *cc_relname;		/* name of relation the tuples come from */
	bool		cc_relisshared; /* is relation shared across databases? */
	ScanKeyData cc_skey[CATCACHE_MAXKEYS];	/* precomputed key info for heap scans */
	...
}
2.2 catcache中缓存元组的组织

每个catcache元素中cc_bucket数组是一个Hash桶数组,元组的键值可以通过hash函数映射到cc_bucket数组的下标。每个hash桶都被组织成一个双向链表Dllist,其中的节点为Dlelem类型,Dlelem是一个包装过的缓存元组,其dle_val字段指向一个CatCTup形式的缓存元组。
在这里插入图片描述

CatCache中的缓存元组将先包装成CatCTup形式,然后再包装成Dlelem形式,最后加入到其所在的hash桶链表中。

typedef struct dlist_node dlist_node;
struct dlist_node
{
	dlist_node *prev;
	dlist_node *next;
};
typedef struct catctup
{
	int			ct_magic;		/* for identifying CatCTup entries */
#define CT_MAGIC   0x57261502
	uint32		hash_value;		/* hash value for this tuple's keys */
	Datum		keys[CATCACHE_MAXKEYS];
	dlist_node	cache_elem;		/* list member of per-bucket list */
	int			refcount;		/* number of active references */
	bool		dead;			/* dead but not yet removed? 标记删除*/
	bool		negative;		/* negative cache entry? 表示实际并不存在的元组*/
	HeapTupleData tuple;		/* tuple management header */
	struct catclist *c_list;	/* containing CatCList, or NULL if none */

	CatCache   *my_cache;		/* link to owning catcache */
} CatCTup;
2.3 在catcache中查找元组

在catcache查找元组有两种方式:精确匹配和部分匹配。

  1. 精确匹配

​ 精确匹配由SearchCatCache函数实现:

HeapTuple
SearchCatCache(CatCache *cache,
			   Datum v1,
			   Datum v2,
			   Datum v3,
			   Datum v4);
  • 首先遍历catcacheheader链表,根据系统表名称或者oid查找到系统表对应的catcache元素。
  • 查找元组键值进行hash,根据hash值找到catcache在cc_bucket数组中对应的hash桶下标。
  • 遍历hash桶链表,找到满足需求的Dlelem,并将其结构体中dle_val强制转换为CatCTup类型,CatCTup中的HeapTupleData就是要查找的元组的头部。
  • 将该Dlelem移动到hash桶链表的头部,并将catcache的cc_hits加1。
  • 如果在hash桶链表中没有找到满足条件的元组,需要进一步扫描物理系统表:
    • 如果在物理系统表中查找到元组,将元组包装成Dlelem,添加到hash桶链表的头部;
    • 否则,说明元组不存在,构建一个“负元组”,并将它包装好,添加到hash桶链表的头部。
      在这里插入图片描述

​ 2. 部分匹配

部分匹配由SearchCatCacheList实现:

SearchCatCacheList(CatCache *cache,
				   int nkeys,
				   Datum v1,
				   Datum v2,
				   Datum v3)

该函数返回一个CatCList数据结构,返回的所有结果通过链表的方式管理。

typedef struct catclist
{
	int			cl_magic;		/* for identifying CatCList entries */
#define CL_MAGIC   0x52765103

	uint32		hash_value;		/* hash value for lookup keys */

	dlist_node	cache_elem;		/* list member of per-catcache list */

	/*
	 * Lookup keys for the entry, with the first nkeys elements being valid.
	 * All by-reference are separately allocated.
	 */
	Datum		keys[CATCACHE_MAXKEYS];

	int			refcount;		/* number of active references */
	bool		dead;			/* dead but not yet removed? */
	bool		ordered;		/* members listed in index order? */
	short		nkeys;			/* number of lookup keys specified */
	int			n_members;		/* number of member tuples */
	CatCache   *my_cache;		/* link to owning catcache */
	CatCTup    *members[FLEXIBLE_ARRAY_MEMBER]; /* members */
} CatCList;

查找过程:
在这里插入图片描述

3. RelCache

RelCache存放的不是元组,而是RelationData数据,每一个RelationData结构表示一个表的模式信息,这些信息由系统表元组中的信息构造而来。

typedef struct RelationData
{
	RelFileNode rd_node;		/* relation physical identifier */
	struct SMgrRelationData *rd_smgr;	/* 表的文件句柄 */
。	...
	Form_pg_class rd_rel;		/* 表在pg_class系统表中对应的元组里的信息 */
	TupleDesc	rd_att;			/* 表的元组描述符,描述了表的各个属性 */
	Oid			rd_id;			/* relation's object id */
	List	   *rd_indexlist;	/* list of OIDs of indexes on relation */
	Bitmapset  *rd_indexattr;	/* identifies columns used in indexes */
	Oid			rd_oidindex;	/* OID of unique index on OID, if any */
	...
	Form_pg_index rd_index;		/* pg_index tuple describing this index */
	...
} RelationData;

由于RelationData数据结构是不变的,采用了hash表维持这个结构。这个hash表也是 PG 内部应用最多最广的 hash 数据结构,其性能和稳定性在PostgreSQL 近三十年的生涯中历经磨练。这个 hash表的实现也是非常值得学习的工业级数据结。

动态hash表介绍参考:https://zhmin.github.io/posts/postgresql-dynamic-hash/

3.1 relcache初始化

初始化阶段1:调用RelationCacheInitialize函数进行初始化,创建hash表。

初始化阶段2:将必要的系统表和系统表索引的模式加入到RelCache中,包括pg_class、pg_attribute、pg_proc、pg_type。

3.2 relcache的操作
  1. 插入新打开的表

    当打开新表时,需要把RelationData加入到RelCache中,该操作通过宏RelationCacheInsert来实现。

  2. 查找hash表

    查找hash表通过宏定义RelationIdCacheLookup来实现,调用函数hash_search。

    relation_open
    	RelationIdGetRelation
    		RelationIdCacheLookup(relationId, rd);
    		RelationBuildDesc -- no reldesc in the cache, RelationBuildDesc() build one and add it.
    			RelationBuildTupleDesc
    			....
    			RelationCacheInsert(relation);
    
  3. 从hash表中删除
    从hash表中删除元素通过宏定义RelationCacheDelete实现。

    RelationClearRelation
    		RelationCacheDelete
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1205714.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2019年12月 Scratch(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

一、单选题(共25题,每题2分,共50分) 第1题 下列关于舞台的描述,不正确的是? A:Scratch只能设置一个舞台 B:舞台不能进行编程 C:舞台可以有多个背景 D:舞台上可以有角色 答案:B A选项,scratch只有一个舞台,B选项,可以在舞台区进行编程,例如切换背景,设置背景…

[pytorch]设备选择以及卷积神经网络的应用

0.写在前面: 首先这篇文章还没写完,因为今天要尝试对我之前的一个框架做一个简单的更新迭代,所以目前先更新这么多. 1.关于设备的选择 首先,目前的大多数电脑都是自带一些GPU(图形计算单元,在这里被称之为cuda), 需要安装相关的驱动才能正常使用这些设备和调用他们的具体情况…

在Vue.js中,什么是Vuex?它的作用是什么?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

Model Inspector—软件模型静态规范检查工具

产品概述 Model Inspector(MI)原厂商是韩国Suresoft,是KOLAS国际公认测评机构,旨在提升安全关键领域软件可信度。MI用于开发过程中模型的静态检查,包括规范检查、复杂度度量,提供MAAB、HIS、CG、MISRA_AC_…

C++模拟实现——AVL树

AVL树 1.介绍 AVL树是对搜索二叉树的改进,通过特定的方法使得每个节点的左右子树高度差绝对值不超过1,使得避免出现歪脖子的情况,最核心的实现在于插入值部分是如何去实现平衡调整的,由于前面详细实现和解析过搜索二叉树&#x…

算法笔记-贪心1

算法笔记-贪心 什么是贪心算法分配饼干例题理解二分割字符串最优装箱整数配对最大组合整数分配区间问题买股票的最佳时机区间选点 问题什么是贪心算法 分配饼干例题 //贪心算法 //保证局部最优,从而使最后得到的结果是全局最优的 #include<iostream> #include<a…

No199.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

Android framework添加自定义的Product项目,lunch目标项目

文章目录 Android framework添加自定义的Product项目1.什么是Product&#xff1f;2.定义自己的Product玩一玩 Android framework添加自定义的Product项目 1.什么是Product&#xff1f; 源码目录下输入lunch命令之后&#xff0c;简单理解下面这些列表就是product。用于把系统编…

Transformers 中原生支持的量化方案概述

本文旨在对 transformers 支持的各种量化方案及其优缺点作一个清晰的概述&#xff0c;以助于读者进行方案选择。 目前&#xff0c;量化模型有两个主要的用途: 在较小的设备上进行大模型推理对量化模型进行适配器微调 到目前为止&#xff0c;transformers 已经集成并 原生 支持了…

阿里云添加端口

目录 阿里云添加端口的方法与步骤详解 一、登录阿里云控制台 二、创建安全组 三、添加入站规则 四、添加出站规则 五、完成添加端口操作 也可 1&#xff1a;搜索轻量级服务器 2&#xff1a;点击服务器 3&#xff1a;点击添加规则 4&#xff1a;保存即可 总结 阿里云…

Redis 常用的类型和 API

前言 在当今的软件开发中&#xff0c;数据存储与操作是至关重要的一部分。为了满足日益增长的数据需求和对性能的追求&#xff0c;出现了许多不同类型的数据库。其中&#xff0c;Redis 作为一种基于内存且高性能的键值存储数据库&#xff0c;因其快速的读取速度、丰富的数据结…

Flink SQL --命令行的使用(02)

1、窗口函数&#xff1a; 1、创建表&#xff1a; -- 创建kafka 表 CREATE TABLE bid (bidtime TIMESTAMP(3),price DECIMAL(10, 2) ,item STRING,WATERMARK FOR bidtime AS bidtime ) WITH (connector kafka,topic bid, -- 数据的topicproperties.bootstrap.servers m…

Javaweb之javascript事件的详细解析

1.6 JavaScript事件 1.6.1 事件介绍 如下图所示的百度注册页面&#xff0c;当我们用户输入完内容&#xff0c;百度可以自动的提示我们用户名已经存在还是可以使用。那么百度是怎么知道我们用户名输入完了呢&#xff1f;这就需要用到JavaScript中的事件了。 什么是事件呢&…

拆位线段树 E. XOR on Segment

Problem - E - Codeforces 区间求和&#xff0c;区间异或的操作跟线段树的区间求和、区间相见相似&#xff0c;考虑用线段树。 发现数组初始值最多是1e6&#xff0c;有不到25位&#xff0c;可以知道异或最大值是这些位数全是1的情况。 发现可以对每一位进行运算就和。 我们开…

图论14-最短路径-Dijkstra算法+Bellman-Ford算法+Floyed算法

文章目录 0 代码仓库1 Dijkstra算法2 Dijkstra算法的实现2.1 设置距离数组2.2 找到当前路径的最小值 curdis&#xff0c;及对应的该顶点cur2.3 更新权重2.4 其他接口2.4.1 判断某个顶点的连通性2.4.2 求源点s到某个顶点的最短路径 3使用优先队列优化-Dijkstra算法3.1 设计内部类…

通过Python设置及读取PDF属性,轻松管理PDF文档

PDF文档属性是嵌入在PDF文档中的一些与文档有关的信息&#xff0c;如作者、制作软件、标题、主题等。PDF属性分为默认属性和自定义属性两种&#xff0c;其中默认属性是一些固定的文档信息&#xff0c;部分信息自动生成&#xff08;如文件大小、页数、页面大小等信息&#xff09…

Linux上C++通过LDAP协议使用kerberos认证AES加密连接到AD服务器

一.前言 记录自己在实现这个流程遇到的各种问题&#xff0c;因为我也是看了许多优质的文章以及组内大佬的帮助下才弄成的&#xff0c;这里推荐一个大佬的文章&#xff0c;写的非常优秀&#xff0c;比我这篇文章写得好得很多&#xff0c;最后我也是看这个大佬的代码最终才实现的…

数据运营基础:用户场景营销

一、概述 场景营销模型是顶层模型&#xff0c;是站在用户经营和用户场景角度来制定经营策略的模型。本质上&#xff0c;场景营销模型是在用户使用产品的每个细分场景中通过分析用户需求整合功能、实体和体验等为用户提供服务的模型。 二、场景的起源和特点 数据运营体系在发展…

【C++】日期类实现,与日期计算相关OJ题

文章目录 日期类的设计日期计算相关OJ题HJ73 计算日期到天数转换KY111 日期差值KY222 打印日期KY258 日期累加 在软件开发中&#xff0c;处理日期是一项常见的任务。为了方便地操作日期&#xff0c;我们可以使用C编程语言来创建一个简单的日期类。在本文中&#xff0c;我们将介…

[工业自动化-18]:西门子S7-15xxx编程 - 软件编程 - PLC用于工业领域的嵌入式系统:硬件原理图、指令系统、系统软件架构、开发架构等

目录 前言&#xff1a; 一、PLC的硬件电路原理 1.1 硬件框图 1.2 硬件模块详解 &#xff08;1&#xff09;CPU &#xff08;2&#xff09;存储器 &#xff08;3&#xff09;输入/输出&#xff08;I/O&#xff09;模块 &#xff08;4&#xff09;编程器 &#xff08;5&a…