【数据库内核分析系列】:数据库表的创建过程
在数据库中,除了DML之外的所有查询都通过ProcessUtility模块来执行,包括了各类DDL语句、事务相关语句、游标相关语句等。上层调用函数为exec_simple_query函数,其中PortalStart函数和PortalDrop函数部分较为简单。核心函数是PortalRun函数下层调用的standard_ProcessUtility函数,该函数通过switch case语句处理了各种类型的查询语句,包括事务相关查询、游标相关查询、schema相关操作、表空间相关操作、表定义相关操作等。 standard_ProcessUtility函数会根据nodeTag(parsetree)的值来确定sql的操作类型,create table一般都是进入T_CreateStmt分支,调用CreateCommand函数。
`void standard_ProcessUtility(Node* parse_tree, const char* query_string, ParamListInfo params, bool is_top_level, DestReceiver* dest, #ifdef PGXC bool sent_to_remote, #endif /* PGXC / char completion_tag, bool isCTAS) { …… errno_t errorno = EOK; switch (nodeTag(parse_tree)) { // 根据nodeTag(parsetree)的值来确定sql的操作类型 …… case T_CreateStmt: { // create table #ifdef PGXC CreateCommand((CreateStmt*)parse_tree, query_string, params, is_top_level, sent_to_remote, isCTAS); #else CreateCommand((CreateStmt*)parse_tree, query_string, params, is_top_level, isCTAS); #endif } break; ……
`
CreateCommand函数先解析parse_tree获取stmt,如果stmt为空则表明表已经存在。如果stmt不为空对stmts进行遍历,如果是 CreateStmt就调用DefineRelation。AlterTableCreateToastTable判断是否需要创建toast表并创建,AlterCStoreCreateTables判断是否需要创建列存表并创建。
`#ifdef PGXC void CreateCommand(CreateStmt *parse_tree, const char *query_string, ParamListInfo params, bool is_top_level, bool sent_to_remote, bool isCTAS) #else void CreateCommand(CreateStmt parse_tree, const char query_string, ParamListInfo params, bool is_top_level, bool isCTAS) #endif { …… / Run parse analysis ... / if (u_sess->attr.attr_sql.enable_parallel_ddl) // 先解析parse_tree获取stmt stmts = transformCreateStmt((CreateStmt)parse_tree, query_string, NIL, true, &namespace_id, is_first_node); else stmts = transformCreateStmt((CreateStmt)parse_tree, query_string, NIL, false, &namespace_id);
/* * If stmts is NULL, then the table is exists. * we need record that for searching the group of table. */ if (stmts == NIL) { // 如果stmt为空则表明表已经存在 table_is_exist = true;
…… /* ... and do it / foreach (l, stmts) { // 遍历stmts Node stmt = (Node*)lfirst(l);
if (IsA(stmt, CreateStmt)) { // 如果是 CreateStmt就调用DefineRelation Datum toast_options; static const char* const validnsps[] = HEAP_RELOPT_NAMESPACES; /* forbid user to set or change inner options */ ForbidOutUsersToSetInnerOptions(((CreateStmt*)stmt)->options); /* Create the table itself */ rel_oid = DefineRelation((CreateStmt*)stmt, ((CreateStmt*)stmt)->relkind == RELKIND_MATVIEW ? RELKIND_MATVIEW : RELKIND_RELATION, InvalidOid, isCTAS);
…… AlterTableCreateToastTable(rel_oid, toast_options, AccessShareLock); AlterCStoreCreateTables(rel_oid, toast_options, (CreateStmt*)stmt); AlterDfsCreateTables(rel_oid, toast_options, (CreateStmt*)stmt); AlterCreateChainTables(rel_oid, toast_options, (CreateStmt *)stmt); ……
`
DefineRelation函数获取到表名relname、名字空间relnamespace、表空间reltablespace、表类型relkind和relpersistence等信息后调用heap_create_with_catalog创建relation。
(gdb) f 0 #0 heap_create_with_catalog (relname=0x7fb4fa872140 "t100", relnamespace=2200, reltablespace=0, relid=0, reltypeid=0, reloftypeid=0, ownerid=10, tupdesc=0x7fb4ff2e2e50, cooked_constraints=0x0, relkind=114 'r', relpersistence=112 'p', shared_relation=false, mapped_relation=false, oidislocal=false, oidinhcount=0, oncommit=ONCOMMIT_NOOP, reloptions=140415352057720, use_user_acl=true, allow_system_table_mods=false, partTableState=0x0, row_compress=1 '\001', bucketinfo=0x0, record_dependce=true, ceLst=0x0, storage_type=HEAP_DISK, partLockMode=1) at heap.cpp:2521
heap_create_with_catalog主要完成表物理文件的创建和表元信息注册到系统表中,涉及系统包包括pg_class,pg_attribute,pg_depend,pg_object,pg_type,pg_index和pg_partition。
其中heap_create内部首先调用了RelationBuildLocalRelation创建RelationData,并加入到relCache,RelationData表示一个表的元信息,这些信息都可以由系统表元组中的信息构造得到。然后根据这些信息通过调用RelalionCreateStorage函数创建物理文件。
附:创建表create table的函数调用栈 #0 RelationCreateStorage #1 heap_create #2 heap_create_with_catalog #3 DefineRelation #4 CreateCommand #5 standard_ProcessUtility #6 gsaudit_ProcessUtility_hook #7 pgaudit_ProcessUtility #8 hypo_utility_hook #9 ProcessUtility #10 PortalRunUtility #11 PortalRunMulti #12 PortalRun #13 exec_simple_query #14 PostgresMain
openGauss: 一款高性能、高安全、高可靠的企业级开源关系型数据库。
🍒如果您觉得博主的文章还不错或者有帮助的话,请关注一下博主,如果三连点赞评论收藏就更好啦!谢谢各位大佬给予的支持!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
获准通过,Fedora 将解决 C 语言历史遗留问题
在半个月前,Fedora 提出了一项新的提议,该提议希望 “将 Fedora 移植到现代 C 语言标准”,如今该提议的状态已被修改成 “接受”,这也意味着这一提议已获得 Fedora 工程和指导委员会(FESCo, Fedora Engineering and Steering Committee)的同意。 提议中写道: 早在 1999 年,C 语言标准的一个新的修订版删除了一些向后兼容的特性,然而 GCC 仍然默认接受这些过时的结构。对这些结构的支持让程序员感到困惑,并有可能影响 GCC 实现未来 C 语言标准中的功能。预计未来的 GCC 版本(可能是 GCC 14)将默认不支持这些传统的语言结构。此更改的目标是让 Fedora 为 GCC 的转变做好准备。 Fedora 设定的目标期限为 Fedora 40 以及 GCC 14 发布之前,根据开发计划,两者都将会在 2024 年发布。开发者也提到,LLVM 也在考虑 2023 年推行类似的举措,因此也将从这些移植工作中受益。然而,LLVM 16 可能会在这项工作结束之前就率先登陆 Fedora,LLVM 团队目前正在研究其他方法。 ...
- 下一篇
【专项测试系列】-缓存击穿、穿透、雪崩专项测试
作者:刘须华 一、背景概述: R2M缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面。而缓存最常见的问题是缓存穿透、击穿和雪崩,在高并发下这三种情况都会有大量请求落到数据库,导致数据库资源占满,引起数据库故障。平时对缓存测试时除了关注增删修改查询等基本功能,应该要重点关注缓存穿透、击穿和雪崩三种异常场景的测试覆盖,避免出现线上事故。 二、基本概念说明: 1、缓存击穿:是指在超级热点数据突然过期,导致针对超级热点的数据请求在过期期间直接打到数据库,这样数据库服务器会因为某一超热数据导致压力过大而崩掉。 2、缓存穿透:是指查找的数据在缓存和数据库中都不存在,导致每一次请求数据从缓存中都获取不到,而将请求打到数据库服务器,但数据库中也没有对应的数据,最后每一次请求都到数据库;如果在高并发场景或有人恶意攻击,就会导致后台数据库服务器压力增大,最终系统可能崩掉。 3、缓存雪崩:是指突然缓存层不可用,导致大量请求直接打到数据库,最终由于数据库压力过大可能导致系统崩掉。缓存层不可用指以下两方面:缓存服务器宕机,系统将请求打到数据库; 缓存数据突然大范围集中过期失效,导致...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Red5直播服务器,属于Java语言的直播服务器
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS7安装Docker,走上虚拟化容器引擎之路
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS关闭SELinux安全模块
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- Linux系统CentOS6、CentOS7手动修改IP地址