Postgresql源码(108)不同类型insert在parse阶段的差异分析

这篇具有很好参考价值的文章主要介绍了Postgresql源码(108)不同类型insert在parse阶段的差异分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

0 概述

分析三种类型的insert在parse的各个阶段的差异:

insert into TAB_IS SELECT * FROM STUDENT a WHERE a.sno > ANY (SELECT b.sno from STUDENT b);
insert into TAB_IS values(10, 'AAA');
insert into TAB_IS values(20, 'CCC'),(30, 'DDD'),(40, 'EEE');

不同insert的计划树type

# T_NestLoopState
insert into TAB_IS SELECT * FROM STUDENT a WHERE a.sno > ANY (SELECT b.sno from STUDENT b);
# T_ResultState
insert into TAB_IS values(10, 'AAA');
# T_ValuesScanState
insert into TAB_IS values(20, 'CCC'),(30, 'DDD'),(40, 'EEE');
# T_FunctionScanState
insert into TAB_IS select i, 'QQQ', i % 10 from generate_series(1, 1000) t(i);
# T_ProjectSetState
insert into TAB_IS values(generate_series(1,10), 'DDD', 1);

1 语义分析差异

下面三种SQL在语义分析结果来看有什么区别?

insert into TAB_IS SELECT * FROM STUDENT a WHERE a.sno > ANY (SELECT b.sno from STUDENT b);
insert into TAB_IS values(10, 'AAA');
insert into TAB_IS values(20, 'CCC'),(30, 'DDD'),(40, 'EEE');

语义分析结果来看,insert语句都会构造插入表和数据表两张表(RangeTblEntry),数据表可能是值构造出来的,或者是select查询出来的。

核心流程都是构造数据表的RangeTblEntry。


代码位置:

transformInsertStmt
	SelectStmt *selectStmt = (SelectStmt *) stmt->selectStmt;

	// 如果selectStmt非空,表示存在select子句
	if (selectStmt == NULL)
		...						// 普通insert
	else if (isGeneralSelect)
		...						// 带select子句
	else if (list_length(selectStmt->valuesLists) > 1)
		...						// 多values

1 insert select语义分析结果

pg_analyze_and_rewrite_fixedparams

insert into TAB_IS SELECT * FROM STUDENT a WHERE a.sno > ANY (SELECT b.sno from STUDENT b);语义分析结果
Postgresql源码(108)不同类型insert在parse阶段的差异分析

2 insert values语义分析结果

insert into TAB_IS values(10, 'AAA');语义分析结果
Postgresql源码(108)不同类型insert在parse阶段的差异分析

3 insert values values语义分析结果

insert into TAB_IS values(20, 'CCC'),(30, 'DDD'),(40, 'EEE');语义分析结果
Postgresql源码(108)不同类型insert在parse阶段的差异分析

2 优化结果差异

一定存在ModifyTable节点,因为这是一个写表操作,也就是会进入ExecModifyTable函数。

ExecModifyTable函数loop下层节点每次拿一条数据,然后执行insert操作。知道下层节点没数据为止。

从ExecModifyTable节点的lefttree可以知道具体是哪种insert。
Postgresql源码(108)不同类型insert在parse阶段的差异分析

3 执行阶段

从执行阶段来看,下面三种SQL有什么区别?

insert into TAB_IS SELECT * FROM STUDENT a WHERE a.sno > ANY (SELECT b.sno from STUDENT b);
                                           QUERY PLAN
-------------------------------------------------------------------------------------------------
 Insert on tab_is  (cost=0.15..208.42 rows=0 width=0)
   ->  Nested Loop Semi Join  (cost=0.15..208.42 rows=367 width=46)
         ->  Seq Scan on student a  (cost=0.00..21.00 rows=1100 width=46)
         ->  Index Only Scan using student_pkey on student b  (cost=0.15..6.62 rows=367 width=4)
               Index Cond: (sno < a.sno)


insert into TAB_IS values(10, 'AAA');
                     QUERY PLAN
----------------------------------------------------
 Insert on tab_is  (cost=0.00..0.01 rows=0 width=0)
   ->  Result  (cost=0.00..0.01 rows=1 width=46)


insert into TAB_IS values(20, 'CCC'),(30, 'DDD'),(40, 'EEE');
                             QUERY PLAN
--------------------------------------------------------------------
 Insert on tab_is  (cost=0.00..0.04 rows=0 width=0)
   ->  Values Scan on "*VALUES*"  (cost=0.00..0.04 rows=3 width=46)

执行阶段没什么区别,都是走ExecModifyTable内部循环搞定。

  1. 每次从lefttree中执行一把拿到一条,subplanstate = outerPlanState(node);context.planSlot = ExecProcNode(subplanstate);
  2. 根据operation类型(insert)执行具体insert操作ExecInsert,比较简单,中间会有slot到tuple的转换。执行器的元组都是包装在slot中的。现在PG的存储引擎提供了AM接口,代码更清晰了。

(执行器层ExecInsert→存储层入口table_tuple_insert)文章来源地址https://www.toymoban.com/news/detail-514060.html

PortalRun
	PortalRunMulti
		ProcessQuery
			CreateQueryDesc
			ExecutorStart
			ExecutorRun
				standard_ExecutorRun
					ExecutePlan
						ExecProcNode
							ExecProcNodeFirst
								ExecModifyTable 
                             -----> ExecProcNode(subplanstate)  --- 
						   /     	switch (operation)              \
						   \			case CMD_INSERT:            /
                             ------------- ExecInsert   <----------
											
										

ps. 测试数据

drop table student;
create table student(sno int primary key, sname varchar(10), ssex int);
insert into student values(1, 'stu1', 0);
insert into student values(2, 'stu2', 1);
insert into student values(3, 'stu3', 1);
insert into student values(4, 'stu4', 0);

drop table course;
create table course(cno int primary key, cname varchar(10), tno int);
insert into course values(10, 'meth', 1);
insert into course values(11, 'english', 2);

drop table teacher;
create table teacher(tno int primary key, tname varchar(10), tsex int);
insert into teacher values(1, 'te1', 1);
insert into teacher values(2, 'te2', 0);

drop table score;
create table score (sno int, cno int, degree int);
insert into score values (1, 10, 100);
insert into score values (1, 11, 89);
insert into score values (2, 10, 99);
insert into score values (2, 11, 90);
insert into score values (3, 10, 87);
insert into score values (3, 11, 20);
insert into score values (4, 10, 60);
insert into score values (4, 11, 70);


SELECT * FROM STUDENT a WHERE a.sno > ANY (SELECT b.sno from STUDENT b); 


drop table TAB_IS;
create table TAB_IS(sno int, sname varchar(10), ssex int);
       
insert into TAB_IS SELECT * FROM STUDENT a WHERE a.sno > ANY (SELECT b.sno from STUDENT b);
insert into TAB_IS values(10, 'AAA');
insert into TAB_IS values(20, 'CCC'),(30, 'DDD'),(40, 'EEE');


到了这里,关于Postgresql源码(108)不同类型insert在parse阶段的差异分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 不同开发语言在进程、线程和协程的设计差异

    在多线程项目开发时,最常用、最常遇到的问题是 1,线程、协程安全 2,线程、协程间的通信和控制 本文主要探讨不同开发语言go、java、python在进程、线程和协程上的设计和开发方式的异同。 进程 进程是 操作系统进行资源分配的基本单位,每个进程都有自己的独立内存空

    2024年01月22日
    浏览(37)
  • 微软 Windows Server 版本对比:了解不同版本之间的差异

    类似于客户端 Windows 版本,Windows Server 也分别提供了各种版本。 Windows Server 是一个操作系统,旨在管理和控制它周围的网络基础架构。每个版本都是针对不同的受众设计的,为他们提供独特的工具和功能,以更有效地管理他们的环境。 此外,它们专为不同尺寸的组织而设计

    2024年02月15日
    浏览(49)
  • Docker内部时间与主机时间不同导致时间差异的解决方法

    Docker内部时间与主机时间不同导致时间差异的解决方法 在使用Docker进行开发或部署应用程序时,我们可能会遇到一个常见的问题,就是Docker容器内部的时间与主机的时间存在差异。这种时间差异可能会导致一些应用程序出现问题,尤其是涉及到时间敏感操作的情况。本文将介

    2024年02月07日
    浏览(41)
  • Java Stream比较两个List的差异,并取出不同的对象

    可以使用Java8的Stream API来比较两个List的差异,并取出不同的对象。   1. 将两个List转换为Stream类型;   2. 调用Stream的filter方法,将不同的对象过滤出来;   3. 将过滤出的不同的对象转换为List类型。         上述代码中,将两个List类型的对象list1和list2转换为Stream类型,并

    2024年02月08日
    浏览(57)
  • 基于 Spring Boot+MySQL实现的在线考试系统源码+数据库,基于不同类型的客观题,进行自动组卷、批卷等功能的考试系统

    一个 JAVA 实现的在线考试系统,主要实现一套基于不同类型的客观题,进行自动组卷、批卷等功能的考试系统(没有主观题) 后端技术栈 基于 Spring Boot 数据库 MySQL ORM MyBatis MyBatis-plus 缓存 Redis 、guava的LoadingCache 安全 Shiro Excel 导出 easyexcel 日志 slf4j、log4j2 图片上传 qiniu 其它工具

    2024年01月22日
    浏览(183)
  • Qt/C++音视频开发50-不同ffmpeg版本之间的差异处理

    ffmpeg的版本众多,从2010年开始计算的项目的话,基本上还在使用的有ffmpeg2/3/4/5/6,最近几年版本彪的比较厉害,直接4/5/6,大版本之间接口有一些变化,特别是一些废弃接口被彻底删除了,而网络上的各种文章几乎都是ffmpeg3左右为主的,所以本人在写这个全功能播放组件的时

    2024年02月14日
    浏览(54)
  • 巨量千川不同阶段人群定向策略使用技巧汇总

    巨量千川不同阶段人群定向策略 一: 人群定向和转化的关系 1: 人群定向 巨量千川中,哪个数据指标最能反应人群价格? 质量高低? 第一个千展: 千次展现平均消耗,本质是平台对人群的定价 编辑切换为居中 第二个客单价: 客单价,本质是人群质量的高低 编辑切换为居中 平台

    2024年02月16日
    浏览(52)
  • Java/Python/Go不同开发语言在进程、线程和协程的设计差异

    在多线程项目开发时,最常用、最常遇到的问题是 1,线程、协程安全 2,线程、协程间的通信和控制 本文主要探讨不同开发语言go、java、python在进程、线程和协程上的设计和开发方式的异同。 进程 进程是 操作系统进行资源分配的基本单位,每个进程都有自己的独立内存空

    2024年01月23日
    浏览(48)
  • TS和JS的差异;ts与js的不同;ts对比js的优势

    TS(TypeScript)是JavaScript的超集,它提供了静态类型检查、类和接口等面向对象编程特性,并且编译成JavaScript运行在浏览器或者Node.js环境中。TS比JS的优势包括: 强类型:TS引入了类型检查,可以在编译阶段发现类型错误,减少程序运行期间的错误。 更好的代码维护性:TS支持

    2024年02月07日
    浏览(48)
  • mysql 5.7 json 类型 json 数组类型 普通字符串类型 10w数据 查询速度差异

    建表语句ddl 10w 数据 插入 存储过程  json 类型 vs 普通字符串类型 建表语句ddl CREATE TABLE tb_json_array_test ( id INT NOT NULL AUTO_INCREMENT, user_no VARCHAR(100), user_name VARCHAR(100), score INT, create_time date, update_time date, remark VARCHAR(100), field1 VARCHAR(100), field2 VARCHAR(100), field3 VARCHAR(100), field4 VARCHAR(

    2024年02月04日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包