一文详解SQL关联子查询

简介: 本文主要介绍什么是关联子查询以及如何将关联子查询改写为普通语义的sql查询。

image.png
本文主要介绍什么是关联子查询以及如何将关联子查询改写为普通语义的sql查询。

在背景介绍中我们将讲讲常见的关联子查询的语义,关联子查询语法的好处以及其执行时对数据库系统的挑战。第二章中我们将主要介绍如何将关联子查询改写为普通的查询的形式,也就是解关联。第三章中我们会介绍解关联中的优化方法。

一 背景介绍

关联子查询是指和外部查询有关联的子查询,具体来说就是在这个子查询里使用了外部查询包含的列。

因为这种可以使用关联列的灵活性,将sql查询写成子查询的形式往往可以极大的简化sql以及使得sql查询的语义更加方便理解。下面我们通过使用tpch schema来举几个例子以说明这一点。tpch schema是一个典型的订单系统的database,包含customer表,orders表,lineitem表等,如下图:

image.png

假如我们希望查询出“所有从来没有下过单的客户的信息”,那么我们可以将关联子查询作为过滤条件。使用关联子查询写出的sql如下。可以看到这里的not exists子查询使用列外部的列c_custkey。

-- 所有从来没有下过单的客户的信息
select c_custkey
fromcustomer
wherenot exists (select*fromorderswhereo_custkey = c_custkey)

如果不写成上面的形式,我们则需要考虑将customer和orders两个表先进行left join,然后再过滤掉没有join上的行,同时我们还需要markorder的每一行,使得本来就是null的那些。查询sql如下:

-- 所有从来没有下过单的客户的信息
select c_custkey
fromcustomerleft join (selectdistinct o_custkeyfromorders) on o_custkey = c_custkey
whereo_custkey is null

从这个简单的例子中就可以看到使用关联子查询降低了sql编写的难度,同时提高了可读性。

除了在exists/in子查询中使用关联列,关联子查询还可以出现在where中作为过滤条件需要的值。比如tpch q17中使用子查询求出一个聚合值作为过滤条件。

-- tpch q17
SELECT Sum(l1.extendedprice) / 7.0 AS avg_yearly 
FROM   lineitem l1, part p
WHERE  p.partkey = l1.partkey AND p.brand = 'Brand#44' AND p.container = 'WRAP PKG' AND l1.quantity < (SELECT 0.2 * Avg(l2.quantity) FROM   lineitem l2WHERE  l2.partkey = p.partkey);

除了出现在where里面,关联子查询可以出现在任何允许出现单行(scalar)的地方,比如select列表里。如果我们需要做报表汇总一些customer的信息,希望对每一个customer查询他们的订单总额,我们可以使用下面包含关联子查询的sql。

-- 客户以及对应的消费总额
selectc_custkey,(select sum(o_totalprice)fromorderswhere o_custkey = c_custkey )
fromcustomer

更复杂一些的比如,我们希望查询每一个customer及其对应的在某个日期前已经签收的订单总额。利用关联子查询只需要做一些小的改变如下:

selectc_custkey,(selectsum(o_totalprice)fromorderswhereo_custkey = c_custkeyand '2020-05-27' > (selectmax(l_receiptdate)fromlineitemwherel_orderkey = o_orderkey) )
fromcustomer

看了这些例子,相信大家都已经感受到使用关联子查询带来的便捷。但是同时关联子查询也带来了执行上的挑战。为了计算关联结果的值(子查询的输出),需要iterative的执行方式。

以之前讨论过的tpch 17为例子:

SELECT Sum(l1.extendedprice) / 7.0 AS avg_yearly 
FROM   lineitem l1, part p
WHERE  p.partkey = l1.partkey AND p.brand = 'Brand#44' AND p.container = 'WRAP PKG' AND l1.quantity < (SELECT 0.2 * Avg(l2.quantity) FROM   lineitem l2WHERE  l2.partkey = p.partkey);

这里的子查询部分使用了外部查询的列 p.partkey。

SELECT 0.2 * Avg(l2.quantity) 
FROM   lineitem l2
WHERE  l2.partkey = p.partkey  -- p.partkey是外部查询的列

优化器将这个查询表示为如下图的逻辑树:

image.png

如果数据库系统不支持查看逻辑树,可以通过explain命令查看物理计划,一般输出如下图:

+---------------+
| Plan Details  |
+---------------+1- Output[avg_yearly] avg_yearly := expr2    -> Project[] expr := (`sum` / DOUBLE '7.0')3        - Aggregate sum := `sum`(`extendedprice`)4            -> Filter[p.`partkey` = l1.`partkey` AND `brand` = 'Brand#51' AND `container` = 'WRAP PACK' AND `quantity` < `result`]5                - CorrelatedJoin[[p.`partkey`]]6                    - CrossJoin7                        - TableScan[tpch:lineitem l1]8                        - TableScan[tpch:part p]9                    - Scalar
10                        -> Project[] result := (DOUBLE '0.2' * `avg`)
11                            - Aggregate avg := `avg`(`quantity`)
12                                -> Filter[(p.`partkey` = l2`partkey`)] 
13                                    - TableScan[tpch:lineitem l2]

我们将这个连接外部查询和子查询的算子叫做CorrelatedJoin(也被称之为lateral join, dependent join等等。它的左子树我们称之为外部查询(input),右子树称之为子查询(subquery)。子查询中出现的外部的列叫做关联列。在栗子中关联列为p.partkey。

例子中对应的逻辑计划和相关定义如下图所示,explain返回结果中第6-8行为外部查询,9-13行为子查询,关联部位在子查询中第12行的filter。

image.png

这个算子的输出等价于一种iterative的执行的结果。也就将左子树的每一行关联列的值带入到右子树中进行计算并返回一行结果。有些类似将子查询看成一个user defined function(udf),外部查询的关联列的值作为这个udf的输入参数。需要注意的是,我们需要子查询是确定的,也就是对同样值的关联列,每次运行子查询返回的结果应该是确定的。

在上图的栗子中,如果外部查询有一行的p.partkey的值为25,那么这一行对应的correlatedjoin的输出就是下面这个查询的结果:

-- p.partkey = 25 时对应的子查询为
SELECT 0.2 * Avg(l2.quantity) 
FROM   lineitem l2
WHERE  l2.partkey = 25

image.png
image.png

需要注意的是,如果计算结果为空集,则返回一行null。而如果运行中子查询返回了超过一行的结果,应该报运行时错误。在逻辑计划里,用enforcesinglerow这个node来约束。

从上面的介绍中可以发现,CorrelatedJoin这个算子打破了以往对逻辑树自上而下的执行模式。普通的逻辑树都是从叶子节点往根结点执行的,但是CorreltedJoin的右子树会被带入左子树的行的值反复的执行。

correlatedjoinnode的输出就是在外部查询的结果上增加了一列,但是可以看到这种iterative的执行方式的复杂度和将外部查询和子查询关联产生之前的那部分树进行cross join的复杂度相同。

同时,这样iterative的执行方式对分布式数据库系统来说是很大的挑战。因为需要修改执行时调度的逻辑。而且我们可以看到,这样的执行方式如果不进行结果的缓存,会进行很多重复结果的计算。

传统的优化器的优化规则没有特别的针对Correlatedjoin node进行处理,为了支持关联子查询的这种iterative的形式,在优化器初始阶段就会把Correlatedjoin进行等价转换,转换过后的逻辑树用join,aggregation等普通算子来进行关联子查询结果的计算。这个过程被称为解关联(decorrelation/unnesting)。下面一章我们主要介绍常见的解关联的方式。

二 常见的解关联方式

为了方便起见,我们在这一章只讨论scalar关联子查询,就是会输出一列值的关联子查询。

在讨论如何解关联之前,我们总结一下关联子查询的输出有以下特点:

  • correlated join算子的计算结果为在外部查询上增加一列。
  • 增加的那一列的结果为将外部查询关联列的值带入子查询计算得出的。当计算结果超过一行则报错,计算结果为空则补充null。
  • 不同于join算子,correlated join不改变外部查询的其他列(不少行也不膨胀)。

解开关联的关键在于使得子查询获得对应的外部查询的行的值。

表现在计划上,就是将correleted join算子向右下推到产生关联的部位的下面。当correlated join算子的左右子树没有关联列的时候,correlated join算子就可以转换成join算子。这样子查询就通过和外部查询join的方式获得了关联列的值,从而可以自上而下计算,回到原本的计算方式。如下图,下图中rest subquery为在关联产生部位之前的子查询部分。当correlated join 推到产生关联的部位之下,就可以转换为普通的join了。

image.png

correlated join推过的那些算子都是需要进行改写,以保持等价性(上图的栗子中subquery变为了subquery’)。

1 下推规则

论文Orthogonal Optimization of Subqueries and Aggregation[2]给出了将correlatedjoin算子下推到其他算子(filter,project,aggregation,union 等)下面的的等价转换规则。但是文中的correlatedjoin算子是会过滤外部查询的行数的,类似于inner join(论文中称为 )。我们这里讨论更加general的类似于left join的 correlatedjoin (论文中称为 ),并讨论如果要保证外部查询行数不被过滤需要做哪些改写。

由于篇幅限制,下面我们只介绍下推到filter,project,aggregation算子下面的等价规则。

为了简单起见,我们在逻辑树中去掉了enforcesinglerow。

转换1 无关联时转换为join

回顾前文所说,correlated join算子的左子树为input,右子树为subquery。当correlated join的左右子树没有关联的时候,这个时候对外部查询的每一行,子查询的结果都是相同的。

我们就可以把correlated join转换成普通的没有join criteria的leftjoin算子。

image.png

注:需要在subquery上添加enforcesinglerow来保证join语义和correlatedjoin相同(不会造成input的膨胀)。

转换2 简单关联条件时转换为join

当correlated join右子树中最上面的节点为一个关联filter而他的下面无关联时,可以直接将这个filter放到left join的条件中,也可以理解为filter上提。如下图:

image.png

转换3 下推穿过filter

image.png

论文中correlatedjoin*可以直接推过filter。如果需要下推的为correlatedjoin,则需要对filter进行改写,改写成带有case when的project。当subquery的行不满足filter的条件时应输出null。

转换4 下推穿过project

image.png

correlated join下推过project,需要在project中添加input的输出列。

转换5 下推穿过aggregation

image.png

correlated join下推到带有group by的aggregation时,需要对aggregation进行改写。

改写为在aggregation的group by的列中增加外部查询的全部列。这里要求外部查询一定有key,如果没有则需要生成临时的key。生成可以的算子在图中为assignuniqueid算子。

如果aggregation为全局的,那么还需要进行额外的处理。如下图:

image.png

correlated join下推到全局aggregation的时候,需要对aggregation增加input的列(以及key)作为group by的列。这个下推规则还需要一个前提,那就是aggregation函数需要满足满足特性 agg(Ø)=agg(null) 。这个的意思就是aggragtion函数需要对空集和对null的计算结果是相同的。

注:在mysql和AnalyticDB for MySQL(阿里云自研的云原生数据仓库[1],兼容mysql语法,下文简称ADB)的语法里,sum, avg等都不满足这个特性。空集的平均值为0, 而对包含null值的任意集合取平均值结果为null不为0。所以需要mark子查询里的每一行,对空集进行特别的处理,在这里就不展开解释了。

论文Orthogonal Optimization of Subqueries and Aggregation[2]反复运用上面这些规则进行correlatedjoin的下推,直到correlatedjoin可以转换为普通的join。

带入之前的tpch q17的栗子中,我们先使用将correlated join推到子查询中的project下面,查询变为:

image.png

然后下推穿过这个agg,并改写这个agg,如下图:

image.png

这里我们忽略 avg(Ø)!=avg(null) 。如果考虑这个情况,则需要mark子查询全部的行,在correlated join之后根据子查询的结果结合mark的值对空集进行特别处理(将mark了的行的值从null变为0)。感兴趣的读者可以参考下一张中q17的最终计划。

接着直接调用之前的规则2,上提这个filter。这样这个查询就变为普通的没有关联的查询了。

image.png

2 结果复用

回顾上一节所说,子查询的查询结果是带入每一行关联列的值之后计算得出的,那么显而易见相同值的关联列带入子查询中计算出的结果是完全相同的。在上面的栗子中,对同样的p.partkey,correlatedjoin输出的子查询的结果是相等的。如下图中外部查询partkey为25的话产生的关联子查询时是完全相同的,那么结果也自然相同。

image.png

15年Newmann的论文Unnesting Arbitrary Queries[3]介绍了一种方法就是先对外部查询里关联列取distinct,再将correlated join返回的值和原本的外部查询根据关联列进行left join,如下图所示:

image.png

这里的not distinct join的条件对应mysql里面的<=>,null<=>null的结果为true,是可以join到一起的。

带入到之前的例子中如下图所示,对外部查询的关联列partkey先进行distinct,然后带入子查询计算结果,最后再通过join将对应的结果接到原本的外部查询上。

image.png

如果进行了上述转换,那么我们可以认为新的input的关联列永远是distinct的。而现在的correlatedjoin*算子可以允许input的列被过滤。这样做的好处除了对于相同的列不进行重复的子查询的计算之外,主要还有下面两个:

  • 新的外部查询是永远有key的,因为distinct过了。
  • correlatedjoin*算子由于过滤外部查询的列,所以它的下推更为简单(不需要assignuniqueid,不需要保留全部行)。

进行上述的转换后,紧接着再套用之前的等价下推规则,我们又可以将correlatedjoin*下推到一个左右子树没有关联的地方,从而改写为inner join。

如果按照Unnesting Arbitrary Queries[3]的方法进行解关联,需要将input的一部分结果进行复用,这个复用需要执行引擎的支持。需要注意的是,当系统不支持复用的时候,我们需要执行两次input的子树(如下图),这个时候就需要input这颗子树的结果是deterministic的,否则无法用这个方法进行解关联。

image.png

三 关联子查询的优化

在ADB的优化器中,逻辑计划会根据每一条转换规则进行匹配和转换,也就意味着在关联解开之后不需要关心解关联产生的计划的效率而将它直接交给后续的优化规则。但是现实并不是那么的美好,因为后续规则不够完备,以及解关联之后丢失了外部查询和子查询之间的关系,我们希望在解关联的时候就将计划尽可能优化。

1 exists/in/filter关联子查询

在之前的章节中为了简化,我们只讨论了scalar子查询。因为exists/in这些子查询都可以改写成scalar子查询。比如将exists改写为count(*) > 0

但是可以看到,如果子查询的返回结果被用来过滤外部查询的行,实际上会简化整个解关联的过程。所以我们对exists/in这样的子查询进行特殊处理,在语法解析时就进行区分。在解关联的过程中,如果可以使用semijoin/antijoin算子进行解关联则直接解开关联,否则后续会转化成scalar子查询也就是correlatedjoin的形式。

2 关联条件的上提

看到这里会发现,随着correlatedjoin的下推,这个逻辑树会变得更加复杂,所以我们在下推之前会在子查询内部进行关联算子的上提。当这个逻辑就是产生关联的算子越高,correlatedjoin就可以早点推到关联部位的下面。比如下面这个查询:

SELECT t1.c2
FROMt1
WHERE t1.c2 < (SELECT 0.2 * max(t2.x)FROMt2WHERE t2.c1 = t2.c1GROUP BY t2.c1);

这里由于t2.c1 = t2.c1可以推到agg 上面(因为对于子查询这是一个在group by列上的条件),我们就可以进行下面的转换。先把关联的filter上提(有时需要改写),这样就只要把correlatedjoin推过filter,调用转换2就可以了。

image.png

更具体的例子就是前文提到的tpch q17。这里的scalar子查询作用在过滤条件中的情况也可以进行进一步改写。

下图为按照之前说的理论下推correlated join并改写为left join之后的逻辑计划。

image.png
image.png
image.png

而由于这个scalar子查询是作为filter条件的,这种情况下子查询没有结果返回为null对应的外部查询是一定会被过滤掉的。所以correlatedjoin可以直接转为 correlatedjoin*,再加上将filter进行上提,我们可以得到下面的计划。这样改写的好处是可以在join前先进行agg(early agg)。坏处就是如果不小心处理,很容易造成语义不等价造成count bug。

3 代价相关的子查询优化

利用window算子解关联

回顾到目前为止我们讲的这些,是不是印象最深刻的在于correlatedjoin算子是在外部查询上增加一列。而他的这个行为和window算子类似。window算子的语义就是不改变输入的行数,只是在每一行上增加一个在window的frame里计算出的值。所以我们可以利用window算子进行解关联,如果感兴趣可以参考这两篇论文Enhanced Subquery Optimizations in Oracle[4]和 WinMagic : Subquery Elimination Using Window Aggregation[5]。

window解关联的改写就是在外部查询包含子查询中全部的表和条件时,可以直接使用window将子查询的结果拼接到外部查询上。他好处是节约了很多tablescan。比如说tpch q2。可以进行下面的改写:

image.png

这里之所能改写成window是因为外部查询包含了内部查询全部的表和条件。而且agg函数min也满足特性agg(Ø)=agg(null) (如果不满足,需要对行进行mark以及用case when 改写输出)。

可以看到改写后tablescan的数量大大减少。更进一步,优化器后面的优化规则会进行根据primarykey的信息以及agg函数的特性进行join 和 window的顺序交换从而进一步减少window算子输入的数据量(filter-join pushdown)。

image.png

这些好处很多文章里都说了。我们在这里讨论一下这样改写的不好的地方:

  • 比如在pk未能显示提供/agg的函数对duplicates敏感的情况下,window算子会阻挡filter-join的下推,从而打断了joingraph造成join的中间结果变大。
  • 如果改写为两棵子树的join,filter-join可以下推到其中一颗子树上。而进行window改写后,filter-join无法下推。
  • 在pipeline的执行模型下/&使用cte的情况下,扫表获得的收益有限。
  • 传统优化器对join&agg的优化处理/优化规则比对window好/丰富很多。

综上所述,什么时候使用window进行改写关联子查询需要进行收益和代价的估计。

CorrelatedJoin在外部查询中的下推

在将correlatedJoin往子查询方向下推之前,我们会将correlatedjoin先在外部查询中进行下推(比如推过cross join等)。

这样做是因为correlatedJoin永远不会造成数据的膨胀,所以理论上应该早点做。但实际上correlatejoin下推后也可能切割joingraph,从而造成和window改写差不多的问题。

4 等价列的利用

如果在子查询中存在和外部等价的列,那么可以先用这个列改写子查询中的关联列减少关联的地方从而简化查询。下面举一个简单的例子。

Select t1.c2
Fromt1
Wheret1.c3 < (Select min(t2.c3)From t2Where t1.c1 = t2.c1group by t1.c1)-- 在子查询中使用t2.c1 代替 t1.ct进行简化Select t1.c2
Fromt1
Wheret1.c3 < (Select min(t2.c3)From t2Where t1.c1 = t2.c1group by t2.c1)

5 子查询相关的优化规则

一个方面correaltedjoin这个算子的特性给了我们一些进行优化的信息。下面举一些例子:

  1. 经过correaltedjoin算子之后的行数与左子树的行数相同。
  2. enforcesinglerow的输出为1行。
  3. 外部查询的关联列决定(function dependency)correaltedjoin的新增的输出列。
  4. assignuniqueid产生的key具备unique的属性等,可用于之后化简aggregation和group by等。
  5. 子查询里的sort可以被裁剪。

另一个方面,在子查询的改写中,可以通过属性推导进行子查询的化简。比如:

  1. 如果原本外部查询就是unique的则没有别要增加uniqueid列。
  2. enforcesinglerow的子节点的输出如果永远为1行则可以进行裁剪。
  3. 关联列在project上的子查询,如下图,在一些情况下改写为exists子查询。
select t1.orderkey,(selectmin(t1.orderkey)fromorders t2wheret2.orderkey > t1.orderkey)
fromorders t1
order by1

6 需要注意的地方

子查询解关联中最需要注意的地方就是两个地方,一个是确保仅对外部查询进行加一列的操作,一个是对null值的处理。

计数错误

文献中常提到的是一个经典的解关联容易出错的地方。比如下面的查询,我们有一个前提条件就是t1.c3全都是小于0的。在这个情况下子查询参与的关联条件应该是没有任何过滤度的。而改写成inner join则会过滤掉一些行。语义上是不等价的。

Select t1.c2
Fromt1
Wheret1.c3 < (Select COUNT (*)From t2Where t1.c1 = t2.c1)

分布式下的leftmarkjoin

另一个容易出错的地方是论文Unnesting Arbitrary Queries[3]中的LeftMarkJoin,其输出的结果与in的语义相同。简单来说就是下面这个查询的结果。

select t1.c1 in (selectt2.c1fromt2)
fromt1

这个查询对应的逻辑计划如下:

image.png

其输出结果为在左子树结果上加一列in的结果,in的结果有三种可能true,false和null。

在分布式环境下,对这个算子进行repartition和落盘很容易造成和null值相关的计算出错。

举一个简单的例子,当leftmarkjoin为repartition的执行方式时,会对左表和右表的数据根据c1的hash值进行重分布reshuffle。那么t1.c1中为null的行会被shuffle到同一台executor上。这个时候假如右表没有数据被shuffle到这台机器上,那么这一台executor并不知道对于null的这些行该输出null还是false。因为null in空集的结果为false,而null in 任何非空集合的结果为null。此时这台executor并不知道右表是否为空。

解开关联后的效率

在最开始的时候我们提到了iterative的执行方式,这里我们需要说明对有些关联子查询来说即使关联被解开为join/agg等算子,计算查询结果也需要一个cross join的代价。

比如下面这个两个查询, 第一个是我们常见的关联子查询的样子,可以转换成inner join + early agg的形式。而第二个解开关联后则会变成一个left join on非等值条件(代价同cross join)。

-- sql 1
SELECT t1.c1FROM t1WHERE t1.c2 > ( SELECT min(t2.c2) FROM t2 WHERE t2.c1 = t1.c1);-- sql 2
SELECT t1.c1FROM t1WHERE t1.c2 > ( SELECT min(t2.c2) FROM t2 WHERE t2.c1 > t1.c1);

sq1解开关联后的计划如下:
image.png

sql2解开关联后的计划如下:
image.png

对于sql1来说,从语义上理解,外部查询的每一行带入子查询里扫过的行都是没有重叠的,所以代价和innerjoin on等值条件是一样的。再加上同样的外部行对应的子查询中min的结果相同可以应用early agg从而可以进一步优化。

对于sql2来说,从语义上理解,外部查询的每一行都必须要带入子查询中扫过所有的行才能判断在满足t2.c1 > t1.c1这个条件下的子查询的输出应该是什么。为了计算出结果这个代价是无法通过优化节约的。但是对同样的t1.c1输出始终是相同的,Unnesting Arbitrary Queries[3]中的结果复用仍然可以产生优化。

参考文献
[1] https://www.aliyun.com/product/ApsaraDB/ads
[2] Galindo-Legaria,César和Milind Joshi。“子查询和聚合的正交优化。” ACM SIGMOD记录30.2(2001):571-581。
[3] Neumann,Thomas和Alfons Kemper。“取消嵌套任意查询。” 商业,技术和网络数据库系统(BTW 2015)(2015年)。
[4]贝拉姆康达(Bellamkonda),斯里坎特(Srikanth)等。“增强了Oracle中的子查询优化。” VLDB基金会论文集2.2(2009):1366-1377
[5] Zuzarte,Calisto等人。“ Winmagic:使用窗口聚合消除子查询。” 2003 ACM SIGMOD国际数据管理国际会议论文集。2003。
[6] Neumann,Thomas,Viktor Leis和Alfons Kemper。“联接的完整故事(inHyPer)。” 商业,技术和网络数据库系统(BTW 2017)(2017)。
[7]加利福尼亚州加林多-莱加里亚(Galindo-Legaria),参数化查询和嵌套等效项。技术报告,Microsoft,2001年。MSR-TR-2000-31,2000年。

原文链接

本文为阿里云原创内容,未经允许不得转载。

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

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

相关文章

阿里巴巴研究员叔同:云原生是企业数字创新的最短路径

作者&#xff1a;叔同 今天&#xff0c;数字化成为企业的核心竞争力&#xff0c;千行百业都在拥抱云计算&#xff0c;拥抱云原生。2020年我们认为是云原生的落地元年&#xff0c;那么2021年将是云原生加速推动企业数字创新的关键节点。在3月29日阿里云计算峰会上&#xff0c;阿…

Kubernetes 微服务监控体系

作者|无敌码农来源|无敌码农监控系统是运维体系乃至整个软件产品生命周期中最重要的一环&#xff0c;完善的监控可以帮助我们事前及时发现故障&#xff0c;事后快速追查定位问题。而在以微服务为代表的云原生架构体系中&#xff0c;系统分为多个层次&#xff0c;服务之间调用链…

python解zuobiaoxi方程_滑坡稳定性分析程序初探---Python版!

0 前言 山体滑坡是常见的自然灾害&#xff0c;从理论分析的角度讲&#xff0c;滑坡的稳定性分析方法源自于高中物理学&#xff0c;如图1所示。前者的滑动分析非常简单&#xff0c;在已知滑块的重量以及接触面摩擦系数的基础上通过计算下滑力和抗滑力的关系即可分析其稳定性&…

php 动态 控件,PHP技术在动态网页表单控件提取中的应用研究

曲小纳摘要&#xff1a;由于电子商务及网络信息技术的飞速发展&#xff0c;动态网站已经逐渐取代传统的静态网站&#xff0c;在不断向人工智能化等方向发展。该篇文章就针对PHP这种技术在动态网页表单控件提取中的应用进行详细的阐述。关键词&#xff1a;PHP;动态网页;表单中图…

冷启动延时缩短50%-80%,阿里云函数计算发布冷启动加速技术

简介&#xff1a; 近日&#xff0c;阿里云函数计算重磅发布冷启动加速技术&#xff0c;将原本属于开发者的镜像优化负担转由函数计算承担&#xff0c;进一步帮助开发者提高生产效率&#xff0c;专注业务创新。该技术源于阿里集团超大规模和场景高度复杂的容器环境&#xff0c;对…

评审恩仇录——IDE也能做代码评审?

简介&#xff1a; 云效Codeup推出了本地IDE插件端的评审&#xff0c;免除了黄药师来回华山的奔波之苦 现代科技公司的同事们平日一起交流开发规约和产品需求&#xff0c;肩上共同扛着业务发展和同行竞争的压力&#xff0c;这份还书贻剑的情谊如何能引来恩仇呢&#xff1f;通过…

云原生数据仓库TPC-H第一背后的Laser引擎大揭秘

简介&#xff1a; 作者| 魏闯先阿里云数据库资深技术专家 一、ADB PG 和Laser 计算引擎的介绍 &#xff08;一&#xff09;ADB PG 架构 ADB PG 是一款云原生数据仓库&#xff0c;在保证事务ACID 能力的前提下&#xff0c;主要解决云上海 量数据的实时分析问题。它的架构与传…

新云网、5G、Wi-Fi 6 Plus,探秘2021通信展上的锐捷网络黑科技

供稿 | 锐捷网络 出品 | CSDN云计算 2021年9月27日&#xff0c;主题为“创新点亮数字化未来”的第三十届中国国际信息通信展览会&#xff08;PT EXPO 2021&#xff09;在北京如期开幕。展会汇聚业内的科技创新技术专家和优秀企业&#xff0c;共同探讨数字化创新的新趋势、新场…

【OpenYurt 深度解析】边缘网关缓存能力的优雅实现

简介&#xff1a; 阿里云边缘容器服务上线 1 年后&#xff0c;正式开源了云原生边缘计算解决方案 OpenYurt&#xff0c;跟其他开源的容器化边缘计算方案不同的地方在于&#xff1a;OpenYurt 秉持 Extending your native Kubernetes to edge 的理念&#xff0c;对 Kubernetes 系…

python的类名一定要大写吗_python 类名

广告关闭 腾讯云11.11云上盛惠 &#xff0c;精选热门产品助力上云&#xff0c;云服务器首年88元起&#xff0c;买的越多返的越多&#xff0c;最高返5000元&#xff01; 如果我从中执行此操作的函数是实例的类派生的基类&#xff0c;我如何找到在python中创建对象实例的类的名称…

Elasticsearch生态技术峰会 | 阿里云Elasticsearch云原生内核

简介&#xff1a; 开源最大的特征就是开放性&#xff0c;云生态则让开源技术更具开放性与创造性&#xff0c;Elastic 与阿里云的合作正是开源与云生态共生共荣的典范。值此合作三周年之际&#xff0c;我们邀请业界资深人士相聚云端&#xff0c;共话云上Elasticsearch生态与技术…

剑指云原生数据库 2.0,阿里云发布全新一站式敏捷数据仓库解决方案

作为基础软件“三驾马车”之一的数据库&#xff0c;其发展历程可追溯到60年前&#xff1a;从上世纪50年代的层次数据库、网状数据库&#xff0c;70年代的关系型数据库&#xff0c;再到90年代的关系型数据库、数据仓库、PC单机数据库和 2000 年的开源数据库&#xff0c;Oracle等…

深度 | 面向云原生数据湖的元数据管理技术解析

简介&#xff1a; 作者&#xff1a;沐远、明惠 背景 数据湖当前在国内外是比较热的方案&#xff0c;MarketsandMarkets市场调研显示预计数据湖市场规模在2024年会从2019年的79亿美金增长到201亿美金。一些企业已经构建了自己的云原生数据湖方案&#xff0c;有效解决了业务痛点…

sql中“delete from 表名”表示_SQL查询语句知识点总结

为什么要学习SQL?数据分析岗位的基础技能&#xff1a;SQL语句和会使用SQL语句操纵数据库软件&#xff1b;数据量增大的工具需求&#xff1a;excel处理十万以内的数据&#xff1b;数据量增大&#xff0c;需要使用更快速便捷的工具分析数据。SQL知识点总结1数据库基础知识什么是…

Serverless 可观测性的过去、现在与未来

简介&#xff1a; 函数计算可观测性经历了 1.0 -> 2.0 的发展&#xff0c;从闭门造车的可观测发展成开源的可观测&#xff0c;从平台的可观测发展为开发者的可观测&#xff0c;从FaaS Only 的可观测演进成了云原生的可观测。 作者&#xff1a;夏莞 背景 Serverless 将成为…

Gartner:全行业投入人工智能,计算机视觉占比最高

编辑 | 宋慧 供稿 | Gartner Gartner最近一项新调研发现&#xff0c;三分之一拥有人工智能&#xff08;AI&#xff09;技术计划的技术和服务提供商企业机构表示&#xff0c;他们在未来两年对人工智能技术的投资将达到100万美元以上。绝大多数将人工智能技术作为主要投资领域的…

爱奇艺大数据生态的实时化建设

简介&#xff1a; 实时化是大数据未来最重要的方向之一。 作者&#xff5c;爱奇艺大数据团队 数据作为互联网时代的基础生产资料&#xff0c;在各大公司企业拥有举足轻重的地位。数据的价值在互联网公司的体现&#xff0c;大致而言可以分成三类&#xff1a; 发掘数据中的信息…

python机械臂仿真_基于Python的3R机器人运动仿真

一、问题描述 如右图所示的三自由度机械臂&#xff0c;关节1和关节2相互垂直&#xff0c;关节2和关节3相互平行。如图所示&#xff0c;所有关节均处于初始状态。 要求: (1) 定义并标注出各关节的正方向&#xff1b; (2) 定义机器人基坐标系&#xff5b;0&#xff5d;及连杆坐标…

AI 事件驱动场景 Serverless 实践

简介&#xff1a; 事件驱动是指事件在持续事务管理过程中&#xff0c;进行决策的一种策略。可以通过调动可用资源执行相关任务&#xff0c;从而解决不断出现的问题。通俗地说是当用户触发使用行为时对用户行为的响应。在 Serverless 场景下&#xff0c;事件驱动完美符合其设计初…

运维质变育新机,华为云能否引领政企运维破局?

头图 | 付费下载于视觉中国 提到IT运维&#xff0c;我们马上想到的&#xff0c;就是“7*24小时待命”、“救火”。作为IT安全运行的保障&#xff0c;长久以来&#xff0c;运维一直都是“不出事看不到价值&#xff0c;一出事全是锅”的角色。例如某企业自动化运维失效导致宕机…