greenplum 存储过程_揭秘!Greenplum并行执行引擎到底是如何工作的?

65b9f8c4745a75eab208186f175edd57.gif

《深入浅出Greenplum内核》系列直播以每月一场的速度持续推出中。在第一场《架构解读》直播里,我们了解了Greenplum的整体架构、存储管理、索引、查询执行、事务与日志等内容。今天(5月22日),第二场《Greenplum内核揭秘之执行引擎》也顺利播出啦!现在,我们来回顾一下直播演讲内容吧!

看完别忘了前往askGP做一下小测试(ask.greenplum.cn/exam)巩固一下所学的知识点哦!b0bd152a2bcac26ccb72991c68d34fd0.png

感谢大家参加Greenplum的直播活动!在《深入浅出Greenplum内核》系列活动的第二场直播中,我们为大家详细介绍了Greenplum执行器内容,以及Greenplum为了完成执行计划而设计的两个特殊模块Dispatcher和Interconnect等内容。

执行器

首先我们先来了解一下什么是执行器。简单来讲,执行器是处理一个由执行计划节点组成的树,并返回查询结果。那么什么是执行计划节点呢?从本质上讲,一个执行计划节点,实际上就是一个数据处理节点。从下图可看到,在数据输入后,执行节点会对数据进行数据处理,然后返回数据作为输出。这些执行节点会被组织成树的形式。

5c75474049032f8aba07a0f3ecb253fa.png

下图是一个SELECT查询的执行计划树。通过优化器优化后,就会生成这样的树状结构,我们可以看到里面有四个执行节点,包括HashJoin节点,Hash节点,顺序扫描节点,所有的节点通过树的方式组织在一起,来表示各节点之间的数据流动或者顺序关系。  每一个计划节点包含足够多的元数据信息提供给执行器。

图中的Seq Scan被称为原发性的扫描节点,原发性的扫描节点是指,节点本身可以自己产生数据,而不依赖于其他节点;反之,非原发性扫描节点是需要子节点来为其提供数据,图中的Hash Join和Hash就是非原发性扫描节点。了解了原发性扫描节点和非原发性扫描节点的不同,就可以更好的理解后面的执行模型。

344df8baca4a902d866d4364a1eb88c1.png

那么执行器是怎么执行生成的执行计划树呢?就需要利用执行模型了。面对这样的执行计划树时,处理方式其实很多,我们会根据包括每一个节点内的数据输入是怎么样的规定,输出有什么样的特点等不同的信息,会选择不同的执行模型。现在我们来介绍一下几种常见的执行模型。

执行模型

第一种是迭代模型,也被称为流式模型,或者是抽拉式模型。它的定义非常简单,每一个执行节点本质上就是一个next函数,我们会从一个树节点的根节点一直往下执行这个next 函数。next 函数的实现会遵循这样的特点:
  • 从输出角度看,next 函数的每一次调用,执行节点返回一个tuple,没有更多tuple的时候返回一个NULL。

  • 从输入的角度看,执行节点实现一个循环,每次调用子执行节点的next函数来获取它们的输出,并处理它们直到能返回一个tuple或者NULL。

  • 执行控制流方向是自上往下,不断抽拉的方式,由上层节点直接驱动下层节点来进行数据的驱动。而从数据流的角度来看,还是由上层节点往下层节点传输来完成。

这种执行模型的有点在于规则简单,易懂,资源使用少,通用性好,大部分的执行计划节点一般都可以用这种模式来实现。缺点也很显而易见,由于每次迭代只返回一个tuple,迭代次数多,代码局部性较差,同时对CPU cacheline也不是很友好。

708d08345f0a63bf16a4888a2236808b.png

向量化模型

第二种模型就是向量化模型,和迭代模型有一些相似之处,比如每一个执行节点实现一个next函数,但也有其不同之处。每一次迭代,执行节点返回一组tuple而非一个tuple,从而减少迭代次数,可以利用新的硬件特性如SIMD来加快一组tuple的处理。同时一组tuple在不同的节点之间传输,对列存也更加友好。执行节点实现一个循环,每次调用子执行节点的next函数来获取它们的输出,并能够批量的处理数据。执行控制流方向自上而下,采用pull的方式。

f06329a18e474e9767dcdb07203a57d4.png

Push执行模型

第三种模型是目前比较热门的模型——PUSH执行模型。每一个执行节点定义两个函数
  • Produce函数

Produce函数:看起来像是一个执行节点tuple的生产函数,其实不然,对于非自主生产的执行节点,produce函数更像一个控制函数,它不做过多的生产的工作,想反它会立即调用子节点的produce函数。具有自主生产的执行节点(一般为叶子节点),其produce函数名副其实的生产tuple,并驱动父节点的consume函数提取数据。
  • Consume函数

Consume函数:被下层节点驱动调用,接收子节点数据,进行各种运算,并驱动其父节点的consume函数。

现在我们通过一个例子来看一下,下图中有三个节点,一个扫描节点,一个投影节点,一个Join 节点。每个节点都生成了两个函数,一个生产函数,一个消费函数。整个PUSH模型是怎么做的呢?图中的红框标注的为原发性的扫描节点,蓝框标注的是非原发性的扫描节点。非原发性的扫描节点中的生产函数并不做真正的生产工作,而更多是承担了控制工作,会调用它的子节点的生产函数。因此投影节点和Join节点会调用scan的生产函数。由于Scan是原发性的,因此会在生产并得到数据后,开始驱动数据的消耗。

c3a31e1fc749f76b1985da45c982b8c6.png

PUSH模型是由下层的节点驱动上层的节点来完成的。数据流向也是自下而上的。下层驱动模型可以相对容易的转换成由数据驱动的代码。好处就是,上层的操作就会变成本节点的算子,增加代码的局部性。此外,这样的代码可以更方便进一步转换为一个纯计算代码,例如使用LLVM优化等。个人认为这种模型通用性不强,只能做一些局部的优化。

Greenplum使用的是迭代模型,但我们正在积极探索向量化模型和PUSH模型。Greenplum正在开发相应的功能,并提交到PG社区,基本思路是利用custom scan 的可定制特性,实现向量化版本的AGG节点,SORT节点,并替换原有查询执行树中的相应节点。大家对这一块感兴趣也欢迎去相应的邮件列表查看。

4deebef39ee324304af43c31c8e3f8a4.png

而Greenplum执行器面临了更大的挑战,首先Greenplum是MPP架构,意味着大规模的并行计算,每个执行节点就需要更多的处理过程。同一个执行节点就会变成多个处理过程,而数据也会被拆分。执行节点之间进行输入和输出的过程中,需要不同的计算单元进行交换。

Greenplum执行的挑战和解决方案——Motion

ca3130a701a423b680a7f2bd9ee89ee3.png

此外,Greenplum是一个Shared-Nothing的架构,这就意味着不同的计算单元之间的输入输出的过程会受阻。

a7033772c296d8769adfb28a2c469b25.png

面临这样的挑战,Greenplum的解决方案是加了一个新的名为MOTION的执行节点,用来在不同的执行节点之间移动数据。

f5eed08e8cade469e6a4323350fc6418.png

加了Motion后,执行计划仍然是树状结构。只是在不同的节点之间加了个Motion节点,并最终通过Motion节点,将数据进行汇总。

a0deb7bcac4899cc271f42dc9f5d43a8.png

接着我们来剖析一下并行化Plan。在下面的例子中,我们有一个Master和34个Segment节点。现在有两张表:单身男和单身女,数据分布在不同的SEGMENT上。如果我们要进行一个查询,将这两张表格中,籍贯相同的单身男和单身女进行相亲匹配,我们是如何生成一个可以被并行化执行的计划树呢?

为了更好的说明这个问题,我们可以在现实生活中进行映射,来方便大家理解。如果在现实生活中,我们会怎么办?如果这些不同户籍的单身男女在同一个省,此时处理方法就相对简单,

  • 首先把单身女找出来

  • 再把单身男找出来

  • 再把同户籍的男生女生分配到相同的会场

从而较为快速的把这些单身男女进行匹配和筛选。

如果这些单身男女并不在同一个省,而是分布在全国34个省中,此时要如何处理呢?

为了做一个最优的策略,我们会分情况来看,

1. 如果单身男女都居住在户籍所在地

  • 可以由各省独自举办相亲会

  • 针对本省的单身男女组织相亲

  • 将结果返回总部

对应到Greenplum上,是这样的

c16f6fca50dc2c8b1b05ccb875c673e7.png

2. 对于单身女居住在户籍所在地,而单身男生分散在全国各地。此时采取的策略可以是,

  • 各省的分部独自举办相亲会:
  • 将每个省的单身男青年找出来,并将他们通过火车派送回原户籍所在地
  • 由每个省接待这些男青年,并在本省找出女单身青年,对他们进行相亲配对。

如果女生数量很少,此时可以采用的策略是

  • 找到本省所有适龄单身女青年,并为其买好34个省份的车票,每个省份都去一趟。

  • 每个省接待这些单身女青年,并安排其与生活在本省的男青年相亲,找出户籍一致的配对。

对应到Greenplum上,是这样的

fdf07ba4d18bc601fba9477b1c501b65.png

3. 如果单身男女随机分布在全国各地,此时有两种策略策略1:在总部举办相亲会,各省把单身男女通过火车派送回总部,总部接待并安排相亲配对。但由于总部资源有限,一般都不会采取这种策略;策略2:
  • 各分部举办相亲会:

  • 各省找出居住在本省的适龄单身男,并按户籍派送到相应的省。

  • 各省找出居住在本省的适龄单身女,并按户籍派送到相应的省。

  • 各省接待全国归来的男女,进行相亲配对。

对应到Greenplum上,就是这样的:

31e6be434897c71fb457cd808b7b2c73.png

在进行相亲策划后,我们得出了以下经验总结:

  • 人多力量大的原则,尽量利有各省的分部

  • 要首先分析当前男女青年的地域分布

  • 必要时使用交通工具来打破地域的限制

其实在Greenplum里,也采用了类似的处理方式。每一张表都会有数据分布信息,Greenplum支持三种分布策略:键值分布(按列分布)、随机分布、复制分布(数据在所有的segment上都保留了一份数据)。

Greenplum内部采用更通用的Locus信息来表示分布信息,所有的数据集合都会有数据分布状态的。

612d9a0e8703635b13d67242a0235c17.png

Greenplum通过Motion来打破物理上的隔离。包括下图中的四种Motion。Redistribute Motion是通过键值把Tuple在多个节点间进行重分布。Gather/Gather Merge Motion是把不同Segment上的数据聚集到一个节点上,Gather Merge保证了一个有序的收集过程。Broadcase Motion顾名思义就是广播,每个节点都发送一份。Explict Redistribute Motion常用于Update/Delete操作,该类操作需要在数据原来所在的节点上进行更新或删除,保证数据分布不会出现不一致。gp segment id隐藏列保存了数据所在原来节点信息。

并行化Plan

2df198e31e831bf9cdfbb42ad5e54ac2.png

Motion会引起数据的迁移,带来执行代价,所以Greenplum会对需不需要做Motion进行代价评估,评估依据主要是当前数据集合的数据分布状态和在当前数据集合上将要执行的操作。

08e53cce155b5c1171defb60932469a8.png

现在我们通过一个分布式Join的例子来巩固一下。下面是一个简单的inner join。A、B都是按照Hash分布的键值表。也就是数据被分散在各个Segment上,而每个Segment上只有部分数据。要做到A inner join B的完整数据集,就需要把B表全部复制到所有的segment上,和A的部分数据Join。得到的Plan就如下图所示。前面我们提到,在Join完成后,也会有个数据分布。本例中,在Join完成后,还是会通过Hash分布。接着,由于QD会直接和Client进行交互,因此需要把所有的数据Gather到QD上,再由QD发送给Client。而其中的优化过程,会在本《深入浅出Greenplum内核》系列直播后续的课程中细讲,请大家关注。

f6c09064cfbdd5f0099a1ca586915225.png

如果A是一个键值表,B是一个复制表。前面的Broadcast就不需要做了,可以直接进行Join。每个并行处理单元处理下图中的计划树,再Gather到QD即可。

bd43a3ab8061ed1d5dccb6036aa88532.png

如果A是键值表,而B是general的数据分布。B会在每个segment上都能产生1-10的数据,就能满足Join的需求。

9ef86c8ae27f05d758c5c38d4c092ce5.png

如果A不变,而B是一个子查询,是SingleQE的数据分布,即在一个segment上提供这样的数据。其中一种策略就是,把分布各个Segment上的A的数据都Gather到一个Segment上执行。此时Join后的数据模型就会变成SingleQE的数据分布。

4c020888bf5cdd8a5111d000e7741768.png

如果在Inner Join时加个条件,就可以将Broadcast Motion换成Redistribute Motion。让c2这一列按照c1这个Hash重新分布到其他segment上,从而减少数据的移动。

960846a9ab0d094b0062ba6fdf354d1a.png

我们再来看一个要AGG操作的例子,在下面的例子中,对A进行AGG操作,计算c1的count值。此时,我们只需要在每个Segment上做AGG,再Gather到QD即可。

846567e70651ed1160613c2945d6d9bd.png

如果A表是按照C2做分布的(非两阶段),则前面的策略便不可用了。此时,我们可以将A可以按照C1做Redistrbute Motion,在前面提到的操作即可。

1d9211d3acacb70eea491258d60cd3bf.png

Dispatcher

讲完分布式Plan的产生,我们再来看一下Greenplum中为了支持分布式plan而设计的模块。第一个就是Dispatcher。上面提到的相亲的策略,
  • 各省的分部独自举办相亲会。

  • 首先每个省的单身男青年找出来,并将他们通过火车派送回原户籍所在地。

  • 然后每个省接待这些男青年,并在本省找出女单身青年,对他们进行相亲配对。

具体实施起来是怎么样的呢?

d65fa655e6ba07dca9724e0d72ca7666.png

对应到Greenplum上,有了分布式plan,一堆计算资源是如何分配调度和执行起来的呢?

218e3af1220af1c59fb2ff55a0f7c1bc.png

Dispatcher首先要做的就是分配QE资源。从plan的角度来看,会将计划做成SliceTable,SliceTable中会告知Slice2从34个segment来分配资源,而Slice3只需要Segment2来提供资源即可。

07e4d921e90953c5b864766a5bf44492.png

Dispatcher从SliceTable中得到信息后,会去分配资源。它会向CdbComponentDatabases这个component来申请资源,并将得到的资源回写到SliceTable中。原本,SliceTable中只包括了需要在哪几个Segment上起QE资源的较模糊的指令,但在分配完后,每个SliceTable就会得到QE资源具体的节点信息,包括地址和端口等。

a7ba99b597925ce3e060f4ea787367d5.png

Dispatcher分配QE资源通过调用allocateGang()函数完成。GANG大小的分配非常灵活,最小可以只分配一个QE资源,而一般为segment的个数,甚至可以支持大于segment的个数的QE资源,即每个segment可以为一个gang分配多于一个的QE资源。此外QE资源闲置后,并不会被马上回收,而是可以被后续的查询重用,减少了重复分配QE带来的开销。

103ff24c344d2b763b1947b8ca30bc52.png

Dispatcher第二个功能是分发任务。CdbDispatchPlan可以分发并行性化plan的任务,SliceTable也会连同这个分布式plan一起发给QE。这样的话所有的QE通过SliceTable可以找到自己预先被分配属于哪个Gang,以及它的父节点的Gang是哪些以便于建立节点间通信。通过Parent Gang具体的QE描述符,我们就可以知道要把数据传送到哪个端口。也可以分发纯文本的、两阶段提交、查询树的任务。

2b16b2c57a02a64c81c51c153c546881.png

Dispatcher的第三个功能就是协调功能,通过cdbdisp_checkDispatchResult函数来控制QE的状态。有下面四种等待模式。

dcbc5531a9eac27746991069bfe2f427.png

下图就是一个典型的Dispatcher程序。Greenplum内的代码基本都会遵循这样的逻辑:分配上下文-分配资源-发送任务-等待发送的完成-等待QE的状态-销毁上下文。

356e637ca7428da31faf90fb71069598.png

Interconnect

第二个模块就是Interconnect。Greenplum是通过网络在QE之间移动数据,这个网络模块就是Interconnect。在Motion节点被初始化时,发送端和接收端就会建立Interconnect网络连接。在Motion节点执行时,就会通过Interconnect来发送数据。

38958abf9f05de25ad6220b7bdca3b5f.png

下图是Interconnect的分层介绍。从应用层来说,主要任务是发送数据。Interconnect会对Tuple进行包装,将其包装成一个个Chunk。有些Tuple很大,就会进行切割,将其切成多个Chunk。Chunk通过数据包发送给receiver端。应用层还有一些数据流控制的包,包括EOS包,STOP包等。所有的包都会通过系统传输层中的UDPIFC和TCP IC进行传输。

ee08ca886d0309d90d386f2069eebda1.png

UDPIFC是Greenplum自己实现的一种RUDP(Reliable User Datagram Protocol)协议。基于UDP协议开发的,为了支持传输可靠性,实现了重传,乱序处理,重传处理,不匹配处理,流量控制等功能。GPDB当初引入UDPIFC主要为了解决复杂OLAP查询在大集群中使用连接数过多的问题。UDPIFC实际上是一种线程模型。

66093b8c0ddf48f43c198d2883094186.png

后续,我们也可能会增加一些新的Interconnect类型,包括QUIC协议,Proxy协议等,欢迎大家的关注。

8fae52269a090fddff696ef3aa313812.png

关于Hashjoin的内容,由于时间原因,本次分享就不做详细的讲解,如果大家对这一块感兴趣,可以反馈给我们社区,我们可以在后面添加专门的讲解。大家可以参考一下之前Greenplum中文社区公众号发布的关于Hashjoin的文章来了解相关内容。

40e7a73887c7826db1d8e3bf7e1051c3.gif

Greenplum小测试第二期

(ask.greenplum.cn/exam)

参加活动即可获得“青梅称号”,截图分享至朋友圈还有机会获得Greenplum变色杯!

c926c0376661ea72314332bfe035d2cf.png

44ca950a107296d3b1852b2f5a82b831.png

我知道你

在看

72166b3e047e0001c0769c5855da1454.png

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

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

相关文章

和push的区别_还没有理解let 和 const的用法和区别吗,几百字让你立马搞懂

本文主要讲解ES6中变量的相关操作,变量的命名, 讲解 var、 let 、 const 三者的区别正文ES6中的 let 和 const 都是用来声明变量的, 他们与 var 有所区别let 命令我们都知道在for循环中,我们命名的变量 i 一般都只是为了在这个循环…

三种平摊分析的方法分别为_干货|电工必须学会的三极管电路分析方法

三极管有静态和动态两种工作状态。未加信号时三极管的直流工作状态称为静态,此时各极电流称为静态电流,给三极管加入交流信号之后的工作电流称为动态工作电流,这时三极管是交流工作状态,即动态。一个完整的三极管电路分析有四步&a…

休眠后gpio状态_浅谈Digi XBee模块的休眠模式

浅谈Digi XBee模块的休眠模式2020-3-25Digi XBee S2C模块,如果仅连接电源线可以测得,在待机情况下,大约是10.5mA左右的电流,在休眠时的功耗可以低到0.5uA。可以知道,休眠几乎不耗电。在Spec上标的待机功耗会比实测只接…

xodo上的笔记不见了_一起来“终极笔记名场面批发市场”进货吗

俗话说得好,谁都逃不过“真香定律”,三天不见小笔记,想他。不对,不应该叫小笔记,应该叫粉丝起的名字——“【瓶邪黑花】《终极笔记》(原著风/连载)”下面请接受来自粉丝的疯狂打call~自上周《终极笔记》播出&#xff0…

python3学习笔记 雨痕_Python 3 学习笔记:数字和布尔

数字基本类型整数在 Python 编程中,整数就是数学意义上的整数,包括正整数、负整数和零,且它的位数是任意的。根据表示方法的不同,可以分为:二进制整数八进制整数十进制整数十六进制整数浮点数浮点数,即数学…

不越狱换壁纸_那些不舍得换的手机插画壁纸,你还差几张?

酷爱收藏美作的微课菌可以大展拳脚了!分享3位自己收藏的画师作品,绝对每一张都让你舍不得换,手机可以扔,壁纸得先拷贝存起来!开始吧!!多图预警!NO.1:Atey Ghailan&#x…

程序员绩效总结_年终总结怎么写?

每年这时候,都有必要写一下一年的个人工作总结。年终总结或工作总结是个挺重要的事。写好的话,有助于说明自己的工作绩效,绩效好可以多拿年终奖,还有机会争取晋升。另外,一年下来的个人生活也需要总结,这一…

线程停止继续_线程不是你想中断就能中断

这是我2021年的第2篇原创文章,原汁原味的技术之路尽在Jerrycodes为什么不强制停止如何用 interrupt 停止线程sleep 期间能否感受到中断停止线程的方式有几种总结启动线程需要调用 Thread 类的 start() 方法,并在 run() 方法中定义需要执行的任务。启动一…

倒序查10条数据_10 | 怎么给字符串字段加索引?

现在,几乎所有的系统都支持邮箱登录,如何在邮箱这样的字段上建立合理的索引,是我们今天要讨论的问题。假设,你现在维护一个支持邮箱登录的系统,用户表是这么定义的:mysql> create table SUser( ID bigin…

保留小数点后三位_【Meta分析】Stata制作森林图时,如何保留三位小数?

系统评价/Meta分析指全面收集所有相关研究并逐个进行严格评价和分析,再用定性或定量合成的方法对资料进行处理得出综合结论的研究方法。在指导学员的过程中发现初学者在学习过程中常常会碰到许多共性问题,本公众号特此开设专栏解答,希望能够和…

Redis小计(2)

目录 1.exists命令 2.del命令 3.expire/pexpire命令 4.ttl命令 5.redis对于key过期的删除策略 1.exists命令 exists X1 X2 X3 X4:返回四个key存在的个数。 2.del命令 del X1 X2:删除key。 3.expire/pexpire命令 给key设置超时时间。 expire key…

一秒执行一次_《一秒钟》:一贯的粗旷式抓大放小,张艺谋的自命题作业总是要观众自己再做一遍...

还有不变的永远在奔跑的大棉裤花棉袄的圆脸妮子,这是导演张艺谋最新作品《一秒钟》的最直接观感。张艺谋是个善于从普世情怀处挖掘题材的导演。之前诸多现实题材类型作品,诸如讲父子和解的《千里走单骑》、夫妻爱情的《归来》以及《我的父亲母亲》&#…

unity 畸变_unity3d 几种镜头畸变

1.Fisheye distortion 鱼眼镜头解释来自百度百科:鱼眼镜头是一种焦距为16mm或更短的并且视角接近或等于180。 它是一种极端的广角镜头,“鱼眼镜头”是它的俗称。为使镜头达到最大的摄影视角,这种摄影镜头的前镜片直径很短且呈抛物状向镜头前…

mysql 5.5.18下载_MySQL5.7.18下载和安装过程图文详解

MySql下载1、打开官网找到下载路口,这里直接给出下载的地址2、选择64位版本3、直接下载MySql5.7.18.1安装过程1 、运行安装软件,接受协议2、选择默认安装3、下一步到检查环境界面,点击“Execute”执行检查 (可以后面单独下载插件安装)&…

mysql数据库sql注入原理_SQL注入原理解析以及举例1

sql注入是指web应用程序对用户输入数据的合法性没有判断,导致攻击者可以构造不同的sql语句来实现对数据库的操作。sql注入漏洞产生满足条件:1;用户能够控制数据的输入。2;原本需要执行的代码,拼接了用户的输入。举例&a…

mysql存储map数据结构_map数据结构

Go map实现原理 - 恋恋美食的个人空间 - OSCHINA - 中文开源技术交流社区 https://my.oschina.net/renhc/blog/2208417// A header for a Go map.type hmap struct {// Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.// Make sure this…

四因素三水平正交表_做论文要用正交表?我打包送给你

正交试验目前在国内的应用量仍然是比较高的,许多高校毕业生喜欢利用正交试验来获取研究数据,最终完成毕业论文的撰写或者期刊投稿。正交试验方案的设计,必然要用到(标准)正交表。那么大家都是从哪里获取正交表的呢?小兵给这方面的…

plsql视图添加表字段_Oracle-单表多字段查询(不使用*)

环境:Oracle 11g,plsql 14目的:不使用*,查询拥有上百个字段的表的所有字段。懒人大法:在文章末尾。sql实现逻辑:1、首先建一张100个字段以上的表,通过excel的方式将表建好后直接复制粘贴到plsql的建表界面。…

lableimg闪退_CV学习笔记(二十五):数据集标注与制作

最近在做一些数据标注的工作,虽然标注数据比较枯燥,但这也是每个做算法的工程师升级打怪的必由之路。使用一些合适的工具往往可以事半功倍,效率UP。一:数据标注流程二:数据处理的一些小代码1:重命名当得到这…

java线程堆栈_深入JVM剖析Java的线程堆栈

在这篇文章里我将教会你如何分析JVM的线程堆栈以及如何从堆栈信息中找出问题的根因。在我看来线程堆栈分析技术是Java EE产品支持工程师所必须掌握的一门技术。在线程堆栈中存储的信息,通常远超出你的想象,我们可以在工作中善加利用这些信息。我的目标是…