如何利用OceanBase v4.2的 Runtime Filter提升查询效率

news/2024/6/24 0:23:55/文章来源:https://blog.csdn.net/OceanBaseGFBK/article/details/136953902

OceanBase数据库中可使用Hash Join联接算法,这种算法可以依据某些字段对两个表进行等值匹配连接。然而,当涉及连接的表(特别是作为Probe Table的表)数据量较大时,Hash Join的性能会显著下降。针对这一问题,通常采取的方法是运用Runtime Filter来提升查询效率。

本文将详细阐述OceanBase中的Runtime Filter功能,并探讨在4.2版本中该功能的优化细节。

OceanBase中的Runtime Filter能力

Runtime Filter是一种用于优化Hash Join性能的技术,它可以通过减少Hash Join需要Probe的数据量来提高查询的效率。比如,在星形连接的多张维度表和事实表Join的场景中,Runtime Filter是一个非常有效的优化手段。本质上,Runtime Filter是一类过滤器,它可以利用Hash Join的Build过程构建一个轻量的Filter,然后将Filter广播发送给参与Probe的大表,Probe Table可以使用多个Runtime Filter提前在存储层过滤数据,减少真正参与Hash Join及网络传输的数据,从而提高查询效率。

Runtime Filter的数据结构有Bloom Filter、In Filter、Range Filter三种,始终贯穿Runtime Filter的使用类别。下面通过Runtime Filter的各类别来说明Runtime Filter的作用是使用场景。

1、Runtime Filter跨机传输需求场景

首先,按照是否需要跨机传输来看,Runtime Filter可以分为Local和Global两类,无论是Local还是Global,都可以使用这三种结构的Runtime Filter。我们通过explain可以显示当前计划中的Runtime Filter。计划中和Runtime Filter相关的算子有:

JOIN FILTER CREATE: 表示创建 Runtime Filter 的算子,其后面的NAME区分了同一个计划中的多个Runtime Filter
JOIN FILTER USE: 表示使用 Runtime Filter 的算子,拥有相同NAME的JOIN FILTER CREATE和JOIN FILTER USE是一对。由于filter下推逻辑的存在,真正使用Runtime Filter算子一般是其下方的Table Scan算子。PART JOIN FILTER CREATE:表示创建 Part Join Filter 的算子, 其后面的NAME区分了同一个计划中的多个Runtime Filter
PX PARTITION HASH JOIN-FILTER: 表示使用 Part Join Filter 的算子,拥有相同NAME的PART JOIN FILTER CREATE和PX PARTITION HASH JOIN-FILTER是一对。

(1)Local Runtime Filter

Local Runtime Filter意味着Runtime Filter无需经历网络传输,构建的Filter只需要在本地节点计算过滤,这通常适用于Hash Join Probe侧没有Shuffle的场景。下面为Local Runtime Filter计划:

obclient> create table tt1(v1 int, v2 int) partition by hash(v1) partitions 5;
obclient> create table tt2(v1 int, v2 int) partition by hash(v1) partitions 5;
obclient> explain select /*+ px_join_filter(tt2) parallel(4) */ * from tt1 join tt2 on tt1.v1=tt2.v1;
+------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                                         |
+------------------------------------------------------------------------------------------------------------------------------------+
| ==============================================================                                                                     |
| |ID|OPERATOR                  |NAME    |EST.ROWS|EST.TIME(us)|                                                                     |
| --------------------------------------------------------------                                                                     |
| |0 |PX COORDINATOR            |        |1       |7           |                                                                     |
| |1 |└─EXCHANGE OUT DISTR      |:EX10000|1       |6           |                                                                     |
| |2 |  └─PX PARTITION ITERATOR |        |1       |6           |                                                                     |
| |3 |    └─HASH JOIN           |        |1       |6           |                                                                     |
| |4 |      ├─JOIN FILTER CREATE|:RF0000 |1       |3           |                                                                     |
| |5 |      │ └─TABLE FULL SCAN |tt2     |1       |3           |                                                                     |
| |6 |      └─JOIN FILTER USE   |:RF0000 |1       |4           |                                                                     |
| |7 |        └─TABLE FULL SCAN |tt1     |1       |4           |                                                                     |
| ==============================================================                                                                     |
| Outputs & filters:                                                                                                                 |
| -------------------------------------                                                                                              |
|   0 - output([INTERNAL_FUNCTION(tt1.v1, tt1.v2, tt2.v1, tt2.v2)]), filter(nil), rowset=256                                         |
|   1 - output([INTERNAL_FUNCTION(tt1.v1, tt1.v2, tt2.v1, tt2.v2)]), filter(nil), rowset=256                                         |
|       dop=4                                                                                                                        |
|   2 - output([tt1.v1], [tt2.v1], [tt2.v2], [tt1.v2]), filter(nil), rowset=256                                                      |
|       partition wise, force partition granule                                                                                      |
|   3 - output([tt1.v1], [tt2.v1], [tt2.v2], [tt1.v2]), filter(nil), rowset=256                                                      |
|       equal_conds([tt1.v1 = tt2.v1]), other_conds(nil)                                                                             |
|   4 - output([tt2.v1], [tt2.v2]), filter(nil), rowset=256                                                                          |
|       RF_TYPE(in, range, bloom), RF_EXPR[tt2.v1]                                                                                   |
|   5 - output([tt2.v1], [tt2.v2]), filter(nil), rowset=256                                                                          |
|       access([tt2.v1], [tt2.v2]), partitions(p[0-4])                                                                               |
|       is_index_back=false, is_global_index=false,                                                                                  |
|       range_key([tt2.__pk_increment]), range(MIN ; MAX)always true                                                                 |
|   6 - output([tt1.v1], [tt1.v2]), filter(nil), rowset=256                                                                          |
|   7 - output([tt1.v1], [tt1.v2]), filter([RF_IN_FILTER(tt1.v1)], [RF_RANGE_FILTER(tt1.v1)], [RF_BLOOM_FILTER(tt1.v1)]), rowset=256 |
|       access([tt1.v1], [tt1.v2]), partitions(p[0-4])                                                                               |
|       is_index_back=false, is_global_index=false, filter_before_indexback[false,false,false],                                      |
|       range_key([tt1.__pk_increment]), range(MIN ; MAX)always true                                                                 |
+------------------------------------------------------------------------------------------------------------------------------------+
32 rows in set (0.045 sec)

在计划中显示为JOIN FILTER CREATE 和 JOIN FILTER USE的这一对算子就是Runtime Filter。Name为RF0000的4号和6号算子在该计划中构建了一个Local Runtime FIlter,该Filter无需网络传播,仅在本机使用。

(2)Global Runtime FIlter

Global Runtime Filter意味着该Filter需要广播传输给多个执行节点,并且在计划形态中可以按需将Runtime Filter嵌套下压至计划中的任意位置完成过滤。相比Local Runtime Filter,由于节省的代价不仅包括SQL层投影及计算开销,还包括了网络传输,因此往往能获得不错的执行性能提升。下面为Global Runtime Filter计划:

obclient> create table t1 (C1_RAND int, C2_RAND int, C3_RAND int, C4_RAND int, C5_RAND int) partition by hash(C5_RAND) partitions 5;
obclient> create table t2 (C1_RAND int, C2_RAND int, C3_RAND int, C4_RAND int, C5_RAND int) partition by hash(C5_RAND) partitions 5;
obclient> create table t3 (C1_RAND int, C2_RAND int, C3_RAND int, C4_RAND int, C5_RAND int) partition by hash(C5_RAND) partitions 5;
obclient> explain basic select /*+ leading(a (b  c)) parallel(3) use_hash(b) use_hash(c) pq_distribute(c hash hash) px_join_filter(c a)  px_join_filter(c b) */ count(*) from t1 a, t2 b, t3 c where a.C1_RAND=b.C1_RAND and a.C2_RAND = c.C2_RAND and b.C3_RAND = c.C3_RAND;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                                                                       |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ========================================================                                                                                                         |
| |ID|OPERATOR                                  |NAME    |                                                                                                         |
| --------------------------------------------------------                                                                                                         |
| |0 |SCALAR GROUP BY                           |        |                                                                                                         |
| |1 |└─PX COORDINATOR                          |        |                                                                                                         |
| |2 |  └─EXCHANGE OUT DISTR                    |:EX10003|                                                                                                         |
| |3 |    └─MERGE GROUP BY                      |        |                                                                                                         |
| |4 |      └─SHARED HASH JOIN                  |        |                                                                                                         |
| |5 |        ├─JOIN FILTER CREATE              |:RF0001 |                                                                                                         |
| |6 |        │ └─EXCHANGE IN DISTR             |        |                                                                                                         |
| |7 |        │   └─EXCHANGE OUT DISTR (BC2HOST)|:EX10000|                                                                                                         |
| |8 |        │     └─PX BLOCK ITERATOR         |        |                                                                                                         |
| |9 |        │       └─TABLE FULL SCAN         |a       |                                                                                                         |
| |10|        └─HASH JOIN                       |        |                                                                                                         |
| |11|          ├─JOIN FILTER CREATE            |:RF0000 |                                                                                                         |
| |12|          │ └─EXCHANGE IN DISTR           |        |                                                                                                         |
| |13|          │   └─EXCHANGE OUT DISTR (HASH) |:EX10001|                                                                                                         |
| |14|          │     └─PX BLOCK ITERATOR       |        |                                                                                                         |
| |15|          │       └─TABLE FULL SCAN       |b       |                                                                                                         |
| |16|          └─EXCHANGE IN DISTR             |        |                                                                                                         |
| |17|            └─EXCHANGE OUT DISTR (HASH)   |:EX10002|                                                                                                         |
| |18|              └─JOIN FILTER USE           |:RF0000 |                                                                                                         |
| |19|                └─JOIN FILTER USE         |:RF0001 |                                                                                                         |
| |20|                  └─PX BLOCK ITERATOR     |        |                                                                                                         |
| |21|                    └─TABLE FULL SCAN     |c       |                                                                                                         |
| ========================================================                                                                                                         |
| Outputs & filters:                                                                                                                                               |
| -------------------------------------                                                                                                                            |
|   0 - output([T_FUN_COUNT_SUM(T_FUN_COUNT(*))]), filter(nil), rowset=256                                                                                         |
|       group(nil), agg_func([T_FUN_COUNT_SUM(T_FUN_COUNT(*))])                                                                                                    |
|   1 - output([T_FUN_COUNT(*)]), filter(nil), rowset=256                                                                                                          |
|   2 - output([T_FUN_COUNT(*)]), filter(nil), rowset=256                                                                                                          |
|       dop=3                                                                                                                                                      |
|   3 - output([T_FUN_COUNT(*)]), filter(nil), rowset=256                                                                                                          |
|       group(nil), agg_func([T_FUN_COUNT(*)])                                                                                                                     |
|   4 - output(nil), filter(nil), rowset=256                                                                                                                       |
|       equal_conds([a.C1_RAND = b.C1_RAND], [a.C2_RAND = c.C2_RAND]), other_conds(nil)                                                                            |
|   5 - output([a.C2_RAND], [a.C1_RAND]), filter(nil), rowset=256                                                                                                  |
|       RF_TYPE(in, range, bloom), RF_EXPR[a.C2_RAND]                                                                                                              |
|   6 - output([a.C2_RAND], [a.C1_RAND]), filter(nil), rowset=256                                                                                                  |
|   7 - output([a.C2_RAND], [a.C1_RAND]), filter(nil), rowset=256                                                                                                  |
|       dop=3                                                                                                                                                      |
|   8 - output([a.C1_RAND], [a.C2_RAND]), filter(nil), rowset=256                                                                                                  |
|   9 - output([a.C1_RAND], [a.C2_RAND]), filter(nil), rowset=256                                                                                                  |
|       access([a.C1_RAND], [a.C2_RAND]), partitions(p[0-4])                                                                                                       |
|       is_index_back=false, is_global_index=false,                                                                                                                |
|       range_key([a.__pk_increment]), range(MIN ; MAX)always true                                                                                                 |
|  10 - output([b.C1_RAND], [c.C2_RAND]), filter(nil), rowset=256                                                                                                  |
|       equal_conds([b.C3_RAND = c.C3_RAND]), other_conds(nil)                                                                                                     |
|  11 - output([b.C3_RAND], [b.C1_RAND]), filter(nil), rowset=256                                                                                                  |
|       RF_TYPE(in, range, bloom), RF_EXPR[b.C3_RAND]                                                                                                              |
|  12 - output([b.C3_RAND], [b.C1_RAND]), filter(nil), rowset=256                                                                                                  |
|  13 - output([b.C3_RAND], [b.C1_RAND]), filter(nil), rowset=256                                                                                                  |
|       (#keys=1, [b.C3_RAND]), dop=3                                                                                                                              |
|  14 - output([b.C1_RAND], [b.C3_RAND]), filter(nil), rowset=256                                                                                                  |
|  15 - output([b.C1_RAND], [b.C3_RAND]), filter(nil), rowset=256                                                                                                  |
|       access([b.C1_RAND], [b.C3_RAND]), partitions(p[0-4])                                                                                                       |
|       is_index_back=false, is_global_index=false,                                                                                                                |
|       range_key([b.__pk_increment]), range(MIN ; MAX)always true                                                                                                 |
|  16 - output([c.C3_RAND], [c.C2_RAND]), filter(nil), rowset=256                                                                                                  |
|  17 - output([c.C3_RAND], [c.C2_RAND]), filter(nil), rowset=256                                                                                                  |
|       (#keys=1, [c.C3_RAND]), dop=3                                                                                                                              |
|  18 - output([c.C3_RAND], [c.C2_RAND]), filter(nil), rowset=256                                                                                                  |
|  19 - output([c.C3_RAND], [c.C2_RAND]), filter(nil), rowset=256                                                                                                  |
|  20 - output([c.C2_RAND], [c.C3_RAND]), filter(nil), rowset=256                                                                                                  |
|  21 - output([c.C2_RAND], [c.C3_RAND]), filter([RF_IN_FILTER(c.C3_RAND)], [RF_RANGE_FILTER(c.C3_RAND)], [RF_BLOOM_FILTER(c.C3_RAND)], [RF_IN_FILTER(c.C2_RAND)], |
|        [RF_RANGE_FILTER(c.C2_RAND)], [RF_BLOOM_FILTER(c.C2_RAND)]), rowset=256                                                                                   |
|       access([c.C2_RAND], [c.C3_RAND]), partitions(p[0-4])                                                                                                       |
|       is_index_back=false, is_global_index=false, filter_before_indexback[false,false,false,false,false,false],                                                  |
|       range_key([c.__pk_increment]), range(MIN ; MAX)always true                                                                                                 |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
70 rows in set (0.103 sec)

5号算子对应RF0001,11号算子对应RF000,均下推到21号table full scan算子上进行过滤,此过程横跨了多个DFO,需要通过网络传输,属于Global Runtime Filter。

2、Runtime Filter生效功能场景

其次,从Runtime Filter生效的功能而言,Runtime Filter可以分为过滤连接数据的Filter和过滤分区的Filter两类。第一类为普通Runtime Filter,支持三种数据结构;第二类为Part Join Filter,当前仅支持Bloom Filter。下面重点介绍Part Join Filter。

Hash Join的执行流程是左侧数据阻塞建哈希表, 右侧逐行匹配数据。左侧建哈希表会获取左侧所有数据。如果可以获取左侧所有数据关于右侧某表的分区分布特征(按照右表的分区方式计算出左表关于右表的分区id), 那么在右侧扫描该表数据时,可以根据已统计的分区分布特征提前过滤掉不必要的分区,从而提升性能,Part Bloom Filter的引入正是为了优化这一场景。

想要在Hash Join左侧计算出按照右侧某表分区方式的具体分区,Join的连接键必须包含右侧该表的分区键,这是生成Part Bloom Filter的前提。

obclient [mysql]> create table t1(v1 int);
obclient [mysql]> create table t2(v1 int) partition by hash(v1) partitions 5;
obclient [mysql]> explain select /*+ parallel(3) leading(t1 t2) px_part_join_filter(t2)*/ * from t1 join t2 on t1.v1=t2.v1;
+-------------------------------------------------------------------------------+
| Query Plan                                                                    |
+-------------------------------------------------------------------------------+
| =======================================================================       |
| |ID|OPERATOR                           |NAME    |EST.ROWS|EST.TIME(us)|       |
| -----------------------------------------------------------------------       |
| |0 |PX COORDINATOR                     |        |1       |5           |       |
| |1 |└─EXCHANGE OUT DISTR               |:EX10001|1       |4           |       |
| |2 |  └─HASH JOIN                      |        |1       |4           |       |
| |3 |    ├─PART JOIN FILTER CREATE      |:RF0000 |1       |1           |       |
| |4 |    │ └─EXCHANGE IN DISTR          |        |1       |1           |       |
| |5 |    │   └─EXCHANGE OUT DISTR (PKEY)|:EX10000|1       |1           |       |
| |6 |    │     └─PX BLOCK ITERATOR      |        |1       |1           |       |
| |7 |    │       └─TABLE FULL SCAN      |t1      |1       |1           |       |
| |8 |    └─PX PARTITION HASH JOIN-FILTER|:RF0000 |1       |3           |       |
| |9 |      └─TABLE FULL SCAN            |t2      |1       |3           |       |
| =======================================================================       |
| Outputs & filters:                                                            |
| -------------------------------------                                         |
|   0 - output([INTERNAL_FUNCTION(t1.v1, t2.v1)]), filter(nil), rowset=256      |
|   1 - output([INTERNAL_FUNCTION(t1.v1, t2.v1)]), filter(nil), rowset=256      |
|       dop=3                                                                   |
|   2 - output([t1.v1], [t2.v1]), filter(nil), rowset=256                       |
|       equal_conds([t1.v1 = t2.v1]), other_conds(nil)                          |
|   3 - output([t1.v1]), filter(nil), rowset=256                                |
|       RF_TYPE(bloom), RF_EXPR[t1.v1]                                          |
|   4 - output([t1.v1]), filter(nil), rowset=256                                |
|   5 - output([t1.v1]), filter(nil), rowset=256                                |
|       (#keys=1, [t1.v1]), dop=3                                               |
|   6 - output([t1.v1]), filter(nil), rowset=256                                |
|   7 - output([t1.v1]), filter(nil), rowset=256                                |
|       access([t1.v1]), partitions(p0)                                         |
|       is_index_back=false, is_global_index=false,                             |
|       range_key([t1.__pk_increment]), range(MIN ; MAX)always true             |
|   8 - output([t2.v1]), filter(nil), rowset=256                                |
|       affinitize                                                              |
|   9 - output([t2.v1]), filter(nil), rowset=256                                |
|       access([t2.v1]), partitions(p[0-4])                                     |
|       is_index_back=false, is_global_index=false,                             |
|       range_key([t2.__pk_increment]), range(MIN ; MAX)always true             |
+-------------------------------------------------------------------------------+

在计划中显示为 PART JOIN FILTER CREATE 的3号算子和 PX PARTITION HASH JOIN-FILTER的8号算子就是一对Part Join Filter,3号算子创建Part Join Filter,他会应用到8号算子中对t2表的分区进行过滤。

手动分配Runtime Filter

在默认配置下,当Join基于连接键的过滤性高于一定条件时(目前约为60%)会默认创建三种Runtime Filter数据结构:

  • In Filter,内部使用hash表进行过滤判定;
  • Range Filter,内部使用最大最小值进行过滤判定;
  • Bloom Filter,自身就是一种过滤器。

在过滤优先级上,由于In Filter具有最准的过滤性,执行器当In Filter被启用时,其他两种Filter会被自适应关闭,在执行器根据实际NDV值确定是否使用In Filter。此外,每种Filter在实际计算中会根据实时过滤性自适应Disable Filter以及重新Enable Filter。

Runtime Filter的使用场景仅限于Hash Join,当连接类型不为Hash Join时,优化器将不会分配Runtime Filter。一般情况下,优化器会自动分配Runtime Filter,如果优化器并未分配Runtime Filter,大家也可以通过hint手动分配Runtime Filter。

我们可以通过px_join_fitler以及px_part_join_filter来手动打开runtime filter/part join filter。

/*+ px_join_filter(join_right_table_name)*/
/*+ px_part_join_filter(join_right_table_name)*/

也可以通过no_px_join_filter以及px_part_join_filter来手动关闭runtime filter/part join filter。

/*+ no_px_join_filter(join_right_table_name)*/
/*+ no_px_part_join_filter(join_right_table_name)*/

需要注意的是,在并行度为1的场景下,不会分配Runtime Filter,我们需要至少指定并行度为2。

/*+ parallel(2) */

在手动分配Runtime Filter的过程中,会涉及一些系统变量,以下提供了4个系统变量用于在需要场景下调整Runtime Filter执行相关策略。

系统变量1:runtime_filter_type。

-- oracle模式
alter system set runtime_filter_type = 'BLOOM_FILTER,RANGE,IN';
-- mysql模式
set runtime_filter_type = 'BLOOM_FILTER,RANGE,IN';

runtime_filter_type的默认值为'BLOOM_FILTER,RANGE,IN',表示启用三种类型的Runtime Filter,当runtime_filter_type='' 时,表示不启用任何类型的Runtime Filter。一般情况下,不需要特别指定runtime_filter_type类型,使用默认值即可,OceanBase会在优化和执行阶段选择最优的Runtime Filter类型进行过滤。

系统变量2:runtime_filter_max_in_num。

默认为1024,代表In Filter使用的默认NDV为1024。若执行时NDV > runtime_filter_max_in_num,则将在执行器自动关闭In filter。一般情况下,不建议用户将该值设置过大,因为在Build表NDV很大的情况下,In Filter的效果不如Bloom Filter。

系统变量3:runtime_filter_wait_time_ms。

Probe端等待Runtime Filter到达的最大等待时间默认10ms,当Runtime Filter到达后,Probe再吐数据。如果超过runtime_filter_wait_time_ms还未到达,则进入by pass阶段,此时不经Runtime Filter过滤直接开始吐数据;当某个时刻Runtime Filter达到后,Runtime Filter仍然会被启用并执行过滤。一般情况下,该值不需要调整,当实际使用Bloom Filter数据很大,且如果知道过滤性比较好的情况下,可以适当调大该值。

系统变量4:runtime_bloom_filter_max_size。

限制Bloom Filter的最大长度默认2048MB。当用户实际使用中build表的数据过多时,默认的Bloom Filter的最大长度将不能容纳数据,会导致Bloom Filter误判率增加,此时需要调大runtime_bloom_filter_max_size以降低其误判率,提高其过滤性。

OceanBasev4.2 Runtime Filter特性

OceanBase自3.1版本以来,支持了Join Bloom Filter用于在Join中执行器扫描数据时快速过滤数据,在4.0版本中,对于Join键为分区列或者分区列前缀场景支持了Partition Bloom FIlter动态过滤分区,之后又在4.1版本支持了多发Bloom Filter使相邻DFO和单个DFO内部均可生成多对Bloom Filter。

在OceanBase的4.2版本中,Join Filter能力再次扩充,在TPCH/TPCDS等场景中进一步获得性能提升,并将其统一称为Runtime Filter(RF)。具体来说,OceanBase的4.2版本新增了以下能力:

  • Global Runtime Filter,支持跨DFO计划中任意位置下压Runtime Filter。区别于之前版本中只能支持相邻DFO和DFO内部传输Runtime Filter,Global Runtime Filter可以在复杂的星形连接中完成横跨CTE及多个DFO下压。
  • 新增In、Range类型的Runtime Filter。在Join左表Join列NDV较小的情况下, 使用In Filter可以精确过滤右侧大表数据,对于数据为数值类型且连续分布通过构建MIN/MAX的Range Filter能够在存储层尤其是列式存储结构中快速过滤数据。

注意事项

以上就是OceanBase中的Runtime Filter能力及其在4.2版本的优化细节。需要注意的是,当Hash Join的过滤性不足时,使用Runtime Filter并不能解决问题,反而可能会导致轻微性能下降。因此,在选择手动开启Runtime Filter的时候,需要对查询场景进行仔细评估,以确定Runtime Filter是否适用。

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

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

相关文章

第二十章 红黑树

大家应该都接触过平衡二叉树(AVLTree),了解到 AVL 树的性质,其实平衡二叉树最大的作用就是查找,AVL 树的查找、插入和删除在平均和最坏情况下都是 O(logn)。AVL 树的效率就是高在这个地方。如果在 AVL 树中插入或删除节点后,使得高…

JUC:synchronized优化——锁的升级过程(偏向锁->轻量级锁->重量级锁)以及内部实现原理

文章目录 锁的类型轻量级锁重量级锁自旋优化偏向锁偏向锁的细节偏向锁的撤销批量重偏向批量撤销锁消除 锁的类型 重量级锁、轻量级锁、偏向锁。 加锁过程:偏向->轻量级->重量级 轻量级锁 轻量级锁的使用场景:如果一个对象虽然有多线程要加锁&am…

HarmonyOS 应用开发之Actor并发模型对比内存共享并发模型

内存共享并发模型指多线程同时执行复数任务,这些线程依赖同一内存并且都有权限访问,线程访问内存前需要抢占并锁定内存的使用权,没有抢占到内存的线程需要等待其他线程释放使用权再执行。 Actor并发模型每一个线程都是一个独立Actor&#xf…

IDEA无法连接虚拟机中的Redis的解决方案,无法连接Jedis,无法ping通虚拟机的解决方案

首先,笔者先说明一下自身的情况,怎么连接都连不上,网上的教程全部都看了一遍,基本上没用得上的,这篇文章里面的解决方案包括了笔者能在网上找到了最全面的办法总结,最后终于是连上了 目录 一.连接Jedis出错…

大数据学习第十一天(复习linux指令3)

1、su和exit su命令就是用于账户切换的系统命令 基本语法:su[-] [用户名] 1)-表示是否在切换用户后加载变量,建议带上 2)参数:用户名,表示切换用户 3)切换用户后,可以通过exit命令退…

数据结构——lesson12排序之归并排序

💞💞 前言 hello hello~ ,这里是大耳朵土土垚~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 💥个人主页&#x…

【CANN训练营笔记】AscendCL图片分类应用(C++实现)

样例介绍 基于PyTorch框架的ResNet50模型,对*.jpg图片分类,输出各图片所属分类的编号、名称。 环境介绍 华为云AI1s CPU:Intel Xeon Gold 6278C CPU 2.60GHz 内存:8G NPU:Ascend 310 环境准备 下载驱动 wget ht…

小折叠手机无法使用车上的无线充电?车和手机都没问题

最近看到一个案例——一位新入手Pocket 2的机主,发现自己的手机无法在车上进行无线充电。检查了手机和汽车都没问题,折腾大半天结果发现是电磁线圈没对准无线充电的位置。 无线充电的原理是手机的无线充电电磁线圈对准电磁线圈,通过电磁波感…

Wireshark TS | HTTP 传输文件慢问题

问题背景 之前有几篇文章写过关于应用传输慢的问题,延用之前的老套话,应用传输慢是一种比较常见的问题,慢在哪,为什么慢,有时候光从网络数据包分析方面很难回答的一清二楚,毕竟应用的定义范围实在太广&…

汽车租赁(源码+文档)

汽车租赁(小程序、ios、安卓都可部署) 文件包含内容程序简要说明含有功能项目截图客户端登录界面首页订单个人信息我的界面新手指引注册界面车型选择支付界面修改信息 管理端用户管理订单管理分类管理 文件包含内容 1、搭建视频 2、流程图 3、开题报告 …

vue3+threejs新手从零开发卡牌游戏(二十四):添加p2战斗逻辑

用代码模拟p2战斗逻辑,按流程进行步骤拆分: 1.p2抽卡 2.p2召唤怪兽上场 3.p2战斗 其中战斗部分分为几种情况: 情况一:p2场上卡牌由大到小进行排序,按序轮询可以攻击的卡牌,然后攻击p1场上卡牌由大到小…

[蓝桥杯嵌入式]hal库 stm32 (DMA串口1收发,采用空闲中断方法)

前言: 本系列教程将 对应外设原理,HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 所用工具: 1、芯片: STM32G431RBT6 2、STM32CubeMx软件 3、IDE: MDK-Keil软件 4、STM32G4xx…

supersqli-攻防世界

题目 加个报错 1 and 11 #没报错判断为单引号字符注入 爆显位 1 order by 2#回显正常 1 order by 3#报错 说明列数是2 尝试联合查询 -1 union select 1,2# 被过滤了 return preg_match("/select|update|delete|drop|insert|where|\./i",$inject); select|update|d…

SpringBoot+thymeleaf完成视频记忆播放功能

一、背景 1)客户要做一个视频播放功能,要求是系统能够记录观看人员在看视频时能够记录看到了哪个位置,在下次观看视频的时候能够从该位置进行播放。 2)同时,也要能够记录是谁看了视频,看了百分之多少。 说明:由于时间关系和篇幅原因,我们这里只先讨论第一个要求,第…

Lambda表达式,Stream流

文章目录 Lambda表达式作用前提函数式接口特点 语法省略模式和匿名对象类的区别 Stream流思想作用三类方法获取方法单列集合(Collection[List,Set双列集合Map(不能直接获取)数组同一类型元素(Stream中的静态方法) 常见的中间方法终结方法收集方法 Optional类 Lambda表达式 作用…

HarmonyOS 应用开发之通过标准化数据通路实现数据共享

场景介绍 在多对多跨应用数据共享的场景下,需要提供一条数据通路能够接入多个不同应用的数据并共享给其他应用进行读取。 UDMF针对多对多跨应用数据共享的不同业务场景提供了标准化的数据通路,提供了标准化的数据接入与读取接口。 标准化数据通路的定…

3.java openCV4.x 入门-数据类型(CvType)与Scalar

专栏简介 💒个人主页 📰专栏目录 点击上方查看更多内容 📖心灵鸡汤📖我们唯一拥有的就是今天,唯一能把握的也是今天 🧭文章导航🧭 ⬆️ 2.hello openCV ⬇️ 4.待更新 数据类型&#xff…

Leaflet使用多面(MultiPolygon)进行遥感影像掩膜报错解决之道

目录 前言 一、问题初诊断 1、山重水复 2、柳暗花明 3、庖丁解牛 4、问题定位 二、解决多面掩膜问题 1、尝试数据修复 2、实际修复 3、最终效果 三、总结 前言 之前一篇讲解遥感影像掩膜实现:基于SpringBoot和Leaflet的行政区划地图掩膜效果实战&#xff0…

Shell脚本介绍及基本功能

目录 一、什么是Shell 二、什么是Shell脚本 三、echo 四、Hello World 五、Bash的基本功能 1.别名 2.常用快捷键 3.输入输出 4.输出重定向 5.多命令执行 6.管道符 7.通配符和特殊符合 一、什么是Shell Shell是一种命令行解释器,它是操作系统的一部分&a…

MySQL进阶-----SQL提示与覆盖索引

目录 前言 一、SQL提示 1.数据准备 2. SQL的自我选择 3.SQL提示 二、覆盖索引 前言 MySQL进阶篇的索引部分基本上要结束了,这里就剩下SQL提示、覆盖索引、前缀索引以及单例联合索引的内容。那本期的话我们就先讲解SQL提示和覆盖索引先,剩下的内容就…