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模板网!

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

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

相关文章

  • 微软 Windows Server 版本对比:了解不同版本之间的差异

    微软 Windows Server 版本对比:了解不同版本之间的差异

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

    2024年02月15日
    浏览(11)
  • 不同开发语言在进程、线程和协程的设计差异

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

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

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

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

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

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

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

    基于 Spring Boot+MySQL实现的在线考试系统源码+数据库,基于不同类型的客观题,进行自动组卷、批卷等功能的考试系统

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

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

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

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

    巨量千川不同阶段人群定向策略使用技巧汇总

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

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

    Java/Python/Go不同开发语言在进程、线程和协程的设计差异

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

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

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

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

    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日
    浏览(11)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包