为了支持用户对数据库的扩展,目前的PGSQL提供了很多hook来满足用户的需求。
一般说来,数据库提供了多种扩展机制,例如大家最常见的PLSQL,用户使用SQL来开发存储过程,为了更高的效率和更大的灵活性,也可以使用C语言来开发。为了支持用户更深入的扩展数据库,开源的数据库提供了更加灵活的方式。
说到对数据库的扩展,就不可避免要谈到数据库内部的运行机制,因为数据库的扩展是和内部运行细节密切相关的。目前的关系数据库,简单来说,处理一个SQL基本上就是一个三段论:词法语法分析,查询优化,和执行查询。
对于词法语法分析来说,目前的开源数据库普遍借助了开源的词法语法分析工具yacc或是bision,例如PG中语法脚本是sr/backend/parser/gram.y,这个脚本用左递归文法描述了所支持的SQL,在编译的时候,这个脚本会被yacc作为输入来生成词法分析的程序。这个程序主要的作用是讲输入的一个查询处理之后输出一个词法树,具体的词法树取决于输入的SQL,例如如果输入是一个查询,那么输出就是一个SelectStmt,这个数据结构的具体定义见源码。在生成SelectStmt之后,会被转化成一个Query的数据结构,这个是查询优化器的输入。在转化成Query之后,并没有结束词法语法分析,还需要一个查询改写的过程。PG中的查询改写,其实分的不是特别清晰,PG中的查询改写,一部分在优化器之前,一部分在优化器内。在获得了Query但是优化器之前, PG会对基于view的查询进行改写,简单来说,假设一个之前建立了view:create view v1 as select * from t1 where C1 = a,当前的查询是 select * from v1 where c2 = b, 那么词汇此刻,这个查询在语义上会被改写成 select * from (select * from t1 where c1 = a ) where c2 =b 注意,这里说的是语义上,实际的改写细节比较简单,就是讲Query中rangetable使用一个子查询来代替,这个子查询其实是一个Query数据结构,代表了当前的view v1.
在查询优化阶段,planner会为优化做一些改写,例如最明显的就是将subquery和sublink提上来,直接用join来替代,另外还有就是将一些谓词进行正规化,消除重复代码和获得常量等。在完成了这些查询改写之后,planner会先首先为join操作搜索最佳的join顺序,主要是依据代价模型来获取开销最小的顺序,一般会采用动态规划算法,当然可以通过配置来使用遗传算法。在获得了最佳的join顺序之后,PG会为这个顺序生成最下层也是最基础的plan节点,这个基础的plan会告诉executor如何去扫描表。接着,以此为基础,planner生成agg节点,agg节点主要告诉executor如何做聚集操作,注意,agg节点也会告诉executor如何做过滤操作,这些过滤操作不是简单的对列做过滤,而是对涉及到聚集结果的操作,例如having语句。在agg节点基础上,planner一次生成distinct、sort、limit节点。最终得到一棵左深数状的plan。
在执行查询阶段,也是分三步走的:第一步,准备工作,将查询计划中的每个node生成一个对应的PlanState,为每个操作准备好所需要的资源,最终会以递归的方式生成一个左深树状的PlanState;第二步,执行PlanState,执行的方式就是经典教科书中所描述的迭代器模型;第三步,后续清理工作,释放资源。
在粗略描述了PG内部的运行过程之后,我们回到hook这个话题上面来。PG hook目前的使用还不是特别活跃,虽然最近几年的PGCon有相应的ppt。个人觉得主要原因是:一来没有相应的文档介绍,在PG的手册中没有提到,只能从内部的代码中看到;二来使用的门槛比较高,很少有项目需要用到,除非有深度定制的需求,例如定制查询优化器和executor。
简单来说,这些hook可以PG预先定义的一些接口,用户实现了这些接口之后,将程序封装到动态库中,用户将hook的动态库部署到PG可以访问的目录中。PG加载hook有两种方式:一种是在PG启动的时候直接加载,这就需要在配置文件中制定;一种就是手动加载,每次连接PG之后,使用load命令来加载。一旦PG加载了hook之后,每次运行到相应的代码段,发现某个hook存在,那么PG就会直接去调用这个hook。
前面提到PG的运行阶段可以分为词法语法分析、查询优化、查询执行这三个阶段。对于这三个阶段,PG中都预先定义了hook来满足用户的深度定制需求。
在词法语法分析阶段,PG申明了一个hook (src/backend/parser/analyze.c):
post_parse_analyze_hook_type post_parse_analyze_hook = NULL;
post_parse_analyze_hook_type申明是:
typedef void (*post_parse_analyze_hook_type) (ParseState *pstate,Query *query);
这个hook是词法语法分析完成、得到Query之后被调用的,用户可以通过这个hook来改写Query。
在查询优化阶段,PG申明的hook比较多。首当其冲的就是planner_hook,申明在src/backend/optimizer/plan/planner.c中,类型定义是:
typedef PlannedStmt *(*planner_hook_type) (Query *parse,int cursorOptions, ParamListInfo boundParams);
如果你对PG代码很熟悉的话,会发现这就是查询优化器函数的原型。对的,hacker可以通过这个hook来生成查询计划。这个是个非常重量级的hook,如果不是特别有需要,还是别动它的主意,后果自负,O(∩_∩)O~。
前面提到PG一般默认使用动态规划来找最佳的join顺序,这个是PG内置的算法。当然如果为了发paper,出于实验的目的,为了实验下新的算法来找最佳join顺序,你可以考虑实现这个hook——join_search_hook,它的类型定义是:
typedef RelOptInfo *(*join_search_hook_type) (PlannerInfo *root, int levels_needed, List *initial_rels);
这个hook被调用的堆栈 比较深,不是很好找,位于 src/backend/optimizer/path/allpath.c 的make_rel_from_joinlist方法中。
当然,在查询优化阶段,还有其他的hook,这里就不说了,大家可以翻代码。
在查询执行阶段,PG中提供了一些重量级的hook来帮助大家定制executor的行为:
ExecutorStart_hook_type ExecutorStart_hook = NULL;
ExecutorRun_hook_type ExecutorRun_hook = NULL;
ExecutorFinish_hook_type ExecutorFinish_hook = NULL;
ExecutorEnd_hook_type ExecutorEnd_hook = NULL;
这些hook为用户控制executor的初始化、执行、完成、结束提供了接口。
当然,除了上面提到的这些处理查询的hook之外,还有一些比较重要的hook,例如:check_password_hook和ClientAuthentication_hook,具体的申明定义可以看代码。
事实上,PG从若干年之前就开始提供hook了,最早可以追溯到2008年的8.3版本了,这些hook使得用户可以专注于数据库的后端的查询优化和执行,为用户深度定制PG提供了基础。
分享到:
相关推荐
本篇文章将详细探讨如何在pgsql环境中利用MyBatis来生成实体类,从而简化开发过程。 首先,了解MyBatis的基本概念是必要的。MyBatis是一个SQL映射框架,它的核心功能在于将数据库操作与业务逻辑分离,通过XML或注解...
如果看到"pgsql"和"pdo_pgsql"出现在列出的模块中,说明安装已经成功。 通过这种方法,你可以快速地在CentOS上的PHP环境中启用pgsql和pdo_pgsql扩展,无需编译源代码。然而,这种方法适用于已有.so文件的情况,如果...
L 数据库引擎的独特特点2.3 PGSQL 数据库引擎的关键特性PGSQL 数据库引擎拥有许多独特的特点,使其在众多数据库引擎中脱颖而出: 1. 支持复杂数据类型:不同于传统的关系型数据库仅支持基本的数据类型,PGSQL 引擎...
osm2pgsql是一个用于将OpenStreetMap(OSM)数据导入到PostgreSQL数据库的工具,它是OSM数据处理生态中的重要组成部分。OSM是一种开源的地理信息系统,允许用户自由地创建、编辑和分享地理数据。PostgreSQL则是一个...
【pgsql连接工具,版本6.8】是一款专用于管理和操作PostgreSQL数据库的客户端软件,它在数据库管理员和开发人员的工作中扮演着至关重要的角色。PostgreSQL,简称pgsql,是一种功能强大的开源关系型数据库管理系统,...
在本文中,我们将深入探讨如何在Qt 5框架下与PostgreSQL(pgsql)数据库进行通信。Qt是一个跨平台的应用程序开发框架,而PostgreSQL则是一个强大的开源对象关系数据库系统。结合两者,我们可以构建高效、可靠的...
在IT行业中,数据库管理是至关重要的,而PostgreSQL(简称PGSql)作为一款开源的关系型数据库管理系统,因其强大功能和高度可扩展性而备受青睐。本文将深入探讨如何利用特定程序来生成PGSql的表结构文档,这在数据库...
pgsql数据库jdbc驱动jar包
例如,在PostgreSQL的初始版本中就提供了许多常用的钩子,如check_password_hook、ClientAuthentication_hook、ExecutorStart_hook、ExecutorRun_hook、ExecutorFinish_hook、ExecutorEnd_hook和ExecutorCheckPerms_...
在IT行业中,数据库设计是开发过程中至关重要的一环。它涉及到数据结构、关系模型以及业务逻辑的规划,确保数据的有效存储和高效访问。`MySQL`和`PostgreSQL`(pgsql)是两种广泛使用的开源关系型数据库管理系统,它们...
这个示例中,我们定义了一个新的 `Pgsql` 类来继承自 ThinkPHP 的 `Connector` 类,并重写了 `connect` 方法以适应 PostgreSQL 的连接方式。 #### 四、测试验证 完成以上步骤后,可以尝试通过 ThinkPHP 连接到 ...
Step 1: 使用 DBConvert 工具将 PgSQL 数据库中的表结构和数据转至 MySQL 数据库中 在使用 DBConvert 工具时,需要填写必要的信息,然后点击 next,选择需要转换的表和字段。注意,在选择表和字段时,可以根据需要...
在默认情况下,Nacos采用MySQL作为其内置的数据存储,然而在某些项目中,PostgreSQL这种关系型数据库可能被选为首选的数据库系统。因此,"nacos-pgsql"的出现是为了满足那些使用PostgreSQL的项目集成Nacos的需求。 ...
3. **环境变量设置**:为了方便使用pgsql命令行工具,需要在系统环境变量中添加pgsql的bin目录。这样,无论你在哪个目录下,都可以直接运行pgsql命令。 4. **初始化数据库集群**:运行`initdb`命令来创建一个新的...
Shp2pgsql是PostGIS生态系统中的一个关键工具,专门用于将ESRI Shapefile(简称shp文件)的数据导入到PostgreSQL数据库中。Shapefile是一种常见的地理数据格式,包含了矢量地理数据,如地物边界、道路、河流等。Shp2...
当我们谈论“pgsql拼接”时,我们实际上是在讨论如何在PostgreSQL中进行字符串连接操作。这通常涉及到将多个字符串或者数据库查询结果合并成一个单一的字符串。在数据库查询中,拼接操作非常常见,特别是在构建复杂...
标题中的“pgsql12”和“pgsql9.6”指的是PostgreSQL数据库的两个不同版本,分别代表12.8和9.6。PostgreSQL是一种开源的关系型数据库管理系统(RDBMS),以其高度稳定性和强大的功能著称。它支持SQL标准,并提供了...
在IT行业中,C# ASP.NET是一种广泛用于构建高效、可扩展的Web应用程序的框架,而PostgreSQL(简称PgSql)则是一种开源的对象关系型数据库管理系统,以其强大的功能和稳定性受到开发者的青睐。当我们需要在ASP.NET...
在PostgreSQL(简称PGSQL)中,有时我们需要统计数据库中所有表的空字段数量。这在数据分析、数据清洗等场景下非常有用。下面详细介绍如何创建并使用一个自定义函数来实现这一功能。 #### 函数概述 该函数名为`...
osm2pgsql是一款强大的开源工具,主要用于将OpenStreetMap(OSM)的数据导入到PostgreSQL数据库中。OpenStreetMap是一个全球性的、由志愿者维护的地理信息系统,它提供了免费的地图数据,包括道路、建筑、公园、交通...