当前位置: 首页 > news >正文

干货分享,现代列式数据库系统如何设计与实现? | StoneData 论文选读

作者:袁洋 | StoneData 技术架构师

审核:王博

论文链接:columnstoresfntdbs.pdf (harvard.edu)

列存四先驱和 MIT 知名教授 Samuel Madden 于 2013 年在某期刊上写的一篇当时列存相关技术的综述。文章还挺全面也很经典,通过剖析三个经典的现代列存的数据库 C-store、MonetDB、VectorWise,阐述了各项单独技术的来龙去脉和相辅相成的关系。

行式存储 vs 列式存储

在数据库存储引擎侧通常有两类存储模型:

  • 行式存储 NSM(N-ary Storage Model)

  • 列式存储 DSM(Decomposition Storage Model)

1.1 NSM

一般是将一行数据完整的从头到尾连续存储(超长的字段一般会单独存储,行内记录逻辑地址),连续多行构成一个页,页的尾部通常会存储索引来解决 record 不定长时的快速查找问题。

以行为单位存储,再配合以 B+ 树或 SS-Table 作为索引,就能快速通过主键找到相应的行数据。

行式存储对于 OLTP 场景是很自然的:大多数操作都以实体(entity)为单位,即大多为 增删改查 一整行记录,显然把一行数据存在物理上相邻的位置是个很好的选择。

优点

行存在 insert/update/delete/point lookup query (点查)的场景是占优的:因为涉及的行数据是连续存储的,理论上不存在读写放大。

缺点

在读取时,由于会读取大量无效列数据,譬如 select name from R where age < 40,那么对于每次 age 的遍历,除了会将无用的其他数据一起读入,每次读取 record,都可能会引起 cache miss。对 cpu cache 非常不友好。

1.2 DSM

在存储时将多行数据的相同 column 连续存储在一起,相同 column 的数据组成一个一个的块(Block)。

优点

列式存储非常适用于大量复杂查询的数据分析场景,列式数据库相较于传统的行式数据库具有以下优点:

(1)更高的查询效率。由于数据按列存储,当需要查询某一列的数据时,列式数据库只需要读取该列的数据,而不需要读取整行数据,因此查询速度更快。

(2)更好的数据压缩。由于同一列的数据类型相同,因此可以采用更加有效的数据压缩方式,减少存储空间的占用。

(3)更快的并行处理能力。列式数据库可以同时处理多个列,因此可以更好地利用多核处理器和并行计算资源,提高数据处理效率。

缺点

列存在更新场景明显存在缺陷:

每 insert/update/delete 一行数据,需要同时修改多个列(会去更新存在不同位置的 column),带来 IO 放大,且为随机 IO。

1.3 PAX:一个 Cache 友好高效的行列混存方案

可以看到,NSM 和 DSM 都有各自的优劣,所以如何将它们和优点结合起来,就是 PAX 考虑的问题。

  • NSM 能更快速的取出一行记录,这是因为一行的数据相邻保存在同一页

  • DSM 能更好的利用 CPU Cache 以及使用更紧凑的压缩

PAX 全称是 Partition Attributes Across,它的核心思路是:尝试将 DSM 的一些优点引入 NSM,将两者的优点相结合。将一个页划分成多个 minipage,minipage 内按列存储,而一页中的各个 minipage 能组合成完整的若干 relation。

假设有 n 个 attributes,PAX 就会将 page 分成 n 个 mini pages,然后将第一个 attribute 的放在第一个 mini page 上面,第二个放在第二个 mini page,以此类推。

在每个 page 的开头,会存放每个 mini page 的 offset,mini page 对于 Fixed-length attribute 的数据,会使用 F-minipage ,而对于 variable-length attribute 的数据,则会使用 V-minipage。对于 F-minipage 来说,最后会有一个 bit vector 来存放 null value。而对于 V-minipage 来说,最后会保存每个每个 value 的在 mini page 里面的 offset。

一篇关于 PAX 的 paper 供大家进一步学习和研究。

Paper: https://www.vldb.org/conf/2001/P169.pdf

怎么让列式数据库更快

仅仅将数据存储在列中,并不足以让基于列的存储获得全部性能。该论文中花了大量篇幅来分析几个关键的列存数据库加速技术, 如下图所示

根据论文中的这些技术特性,下面我们逐步分析向量化计算,数据压缩,延迟物化 ,连接优化几个部分。

向量化计算

3.1 概念

火山模型(Volcano-style execution)是最早的查询执行引擎,也叫做迭代模型 (iterator model),或 one-tuple-at-a-time。在这种模型中,查询计划是一个由 operator 组成的 DAG,其中每一个 operator 包含三个函数:open,next,close。Open 用于申请资源,比如分配内存,打开文件,close 用于释放资源,next 方法递归的调用子 operator 的 next 方法生成一个元组(tuple,即行 row 在物理上的表示)。

目前主要有两种关于向量化执行引擎的实现方法:

  1. 仍然使用火山模型,只不过一次返回一组列。这种模型的优势是仍然使用(火山模型),这个优化器于执行器模型已经很成熟,剩下需要的工作量就在于如何将一次一 tuple 的处理模式,修改为一次向上返回一组列存行值(例如:100-1000 行)处理方式,难度相对较小

  2. 将整个模型改造成为层次型的执行模式,这种模式需要将优化好的执行计划树,最终转换为编译执行,即,一次调用下来之后,每一层都完成后才向上返回数据,这样能够最大程度的减少各层次节点间的调用次数,提高 CPU 的有效计算效率

上图描述的就是火山模型实现的行存执行引擎与列存执行引擎,其中左边代表的是当前比较流行的传统行存火山模型,右边代表的是列存实现的火山模型,从上图我们可以看到火山模式是从执行计划树的根节点开始向叶子节点递归调用,然后有叶子节点,通常是各种的扫描节点返回一条符合过滤条件的 tuple 给上层节点处理,每一层节点在处理完该 tuple 之后继续网上层节点传递记录(Agg 节点不是立刻往上层节点返回数据,它需要计算完所有的 Tuple,才能继续往上层节点返回,所以这里 AGG 算子在处理好这个 Tuple 之后,又会往下调用扫描算子返回下一条符合过滤条件的记录)。这样处理完整个表的记录之后,AGG 算子会把数据返回到上一层节点继续处理,在整个过程中需要 AGG 算子缓存中间结果。右边列存执行引擎,执行逻辑基本上与左边行存执行引擎一致,但是每次扫描处理的是一组组以 col 组织的列数据集合,这样我们最为直观的观察就是从上层节点向下层节点的调用次数少了。相应的 CPU 的利用率得到了提高,另外数据被组织在一起。可以利用硬件发展带来的一些收益;如 SIMD, 循环优化,将所有数据加载到 CPU 的缓存当中去,提高缓存命中率,提升效率。在列存储与向量化执行引擎的双重优化下,查询执行的速度会有一个非常巨大的飞跃大约 3-5 倍。

向量化执行流程

  1. 将查询进度控制逻辑与数据处理逻辑分开

  2. 每个操作符的 next()方法返回 N 个图元的矢量

  3. 避免产生大量中间结果

论文中阐述了一种观点:在面向块和矢量化处理的视线中,通过在运算符之间传递 缓存行 大小的 元组 块,并且一次对多个值进行操作,而不是使用传统的 一次一个元组 的迭代器,列存储可以实现大幅提高缓存利用率和 CPU 效率。

3.2 向量化执行的优势 

1. 降低解释开销

减少了解释的开销, 与 tuple-at-a-time 模型相比,查询解释器执行的函数调用量减少了一个与矢量大小相等的系数。在 TPC-H Q1 的查询中可以将性能提高两个数量级。

2. 缓存局部性

列数据是连续的,分配的内存块也是连续的,所以在第一次访问时,大块的内存块会被加载到高速缓存中。这使得后续访问数组中的元素变得相对较快。

3. 编译器优化的可能性

自动内存预取、触发编译器来生成 SIMD 指令、有效使用 CPU 缓冲机制

4. 并行内存访问

并行内存访问。通过无序推测生成多个并行未命中的代码的执行速度通常是非矢量化内存查找的四倍

3.5 向量化执行比传统模式的优势

  • 减少了函数调用的开销(调用次数减少 N 倍)

  • 通过调整向量大小来提高缓存局部性能力

  • 避免分支预测,提高并行内存访问速度

  • 编译器有机会进行编译器优化,可以利用 SIMD 指令集加速计算

  • 基于块的算法优化

  • 可以以更小的代价做 Profiling(面向性能分析开销)

适应性执行:动态选择最优实现(多臂老虎机问题)

数据压缩

4.1 Compression Perspectives

同一列的数据放一起信息熵要远低于来自不同列的数据。信息熵越低,数据越高度有序。 压缩算法在信息熵低 (即具有高数据值局部性) 的数据上表现更好;来自同一列的值往往比来自不同列的值有更多的值局部性。value locality 的意思就是某个数据 (数据的内容或者逻辑地址) 被访问地更频繁。

通常情况下,数据库系统的底线目标是性能,即尽可能快地处理一个或多个查询,而不是压缩率。压缩通过减少花在 I/O 上的时间来提高性能。

4.2 压缩带来的优势

  • 按列压缩压缩率远高于按行压缩,如果数据是排序的压缩率会更高

  • 数据库系统的终极目标是性能而不是压缩率。但是数据被压缩后能减少磁盘 IO,减少从内存到 CPU 带宽的使用。从而进一步提高了性能

  • 一些压缩算法会把数据压缩为固定宽度(fixed-width)数组,这样就可以进一步利用 SIMD 来加速

  • 基于频率的分段压缩,每一段数据有更低的信息熵

4.3 压缩算法

4.3.1 RLE, 游程长度压缩算法

RLE, 游程长度压缩算法, 是一种无损数据压缩的形式, 使用值、起始位置、运行长度三要素。其中同一数据值被存储为单一的数据值和计数,而不是作为原始值存储。如果一列的前 42 个元素含有值 M,也就说起始位置为 1, 42 个 M 的长度, 那么这 42 个元素可以被替换成 (M, 1, 42) 的三要素信息。在列式存储中,由于列的数据是连续的,相同值的情况很常见,因此会出现较多的 RLE encoding 机会。

4.3.2 Bit-Vector Encoding 位向量编码算法

位向量编码是为每一个不同的取值生成一个位向量, 根据位向量( 串)中不同的位置取值 0 或 1 来对应并确定不同的原始值。位向量编码算法其实就是位图索引算法,适用于低基数的列,相对于 B 树索引,它的 count,and,or 操作更有效,位图索引位存放的是 0,1 的 bit,相对于 B 树索引,占字节数特别少,不适合 update、insert、delete 频繁的列-因为要一个数据的更新可能会导致 2 个位图向量的更新。bitmap 的思想就是数据压缩。用一个二进制 bit(0 或者 1)去标记某个元素对应的 value, 这就是 bit + map。适用于低基数的列,相对于 B 树索引,它对 count, and, o r 操作更有效,位图索引位存放的是 0,1 的 bit,相对于 B 树索引,占字节数特别少。不适合 update、insert、delete 频繁的列:因为一个数据的更新可能会导致 2 个位图向量的更新。 举例如下

4.3.3 字典编码算法

字典编码就是生成一个“原始值替代值”的对照字典。为了起到压缩的作用, 替代值的长度小于原始值的长度。存储的时候, 只存储替代值而不是原始值, 从而压缩了存储空间

字典编码算法把唯一值编入字典,每一个唯一值都匹配一个序号,而序号用于索引字典,通过存储序号来压缩数据。如果数据表中存在大量的重复/频繁值,那么使用字典编码压缩率高,效果非常好。

关于字典编码的 Paper, 可以看看这个。

Paper: Dictionary Compression for a Scan-Based, Main-Memory Database System

https://publications.systems.ethz.ch/sites/default/files/publications/BernetJanickSpring2010.pdf

举例如下:

延迟物化

5.1 什么是物化?

物化,即将常用元组或可能会用到的逻辑元组从实际物理存储的状态生成为实体化的元组, 也称为物化, 存储在内存中,是包括一个查询结果的数据库对像,它是远程数据的的本地副本,是一个物理表。在随后查询时, 直接读取已经物化的元组, 以提高查询的效率。

5.2 延迟物化

而元组物化有两种方案, 分别是提前物化: 在提交查询之前物化元组; 延时物化: 尽量推迟物化元组的时间, 在查询中间的某个时刻物化元组。对于列数据库来说, 提前物化需要解压所有已经压缩的数据, 其时间和空间的开销是很大的。同时, 提前物化会涉及到很多不必要的列, 有悖列数据库按列存储、按需取用的初衷。因此, 在列数据库领域, 提出了延时物化的思想。

把从各个列中获取的数据重新组装为行的过程称之为 tuple construction,延迟物化的目的就是尽可能推迟 tuple construction 的时机。把这个物化的时机尽量的拖延到整个查询生命周期的后期。

延迟物化意味着在查询执行的前一段时间内,查询执行的模型不是关系代数,而是基于 Column 的。

5.3 延迟物化的收益?

  1. 减少物化的 tuple 数量

  2. 降低 IO、网络、计算压力

  3. 可以在列存(压缩)数据上进行高效计算

  4. 减少内存访问带来的开销

  5. 在扫描数据相对较少的情况下,需要 cache 的数据量更少,此时也会提高整个计算的 cache 命中率,减少 cpu 的消耗

5.4 一个 延迟物化的例子

SQL:

select name from person where id > 10 and age > 20

5.4.1 行存做法

从文件中读出三列的所有数据,物化成行数据:一行行的 person 数据。然后应用两个过滤条件:id > 10 and age > 20,Filter 之后从数据里面抽出 name 字段,作为最后的结果进行 output

5.4.2 列存上,延迟物化的做法

延迟物化的做法是:

  1. 直接在每一个 Column 数据上分别应用过滤条件,从而得到两个满足过滤条件的 bitmap

  2. 然后再把两个 bitmap 做位与操作得到同时满足两个条件的所有的 bitmap

  3. 因为最后需要的是 name 字段,因此拿着这些 position 对 name 字段的数据进行过滤就得到了最终的结果

5.4.3 普通物化和延迟物化对比

这两者的权衡在于,虽然延迟加载能够减少数据的加载量,但需要维护原始数据的位置 ,这样才能找到对应行的其他列的值。然而如果筛选条件(person.id > 10 and person.age > 20)不能大量过滤数据,延迟加载反而低效。

对于这种情况,就需要根据一些统计信息选择合适的加载算法,来最大限度的提高效率。

延迟物化带来的好处

  • 关系代数里面的 selection 和 aggregation 都会产生一些不必要的物化操作,从一种形式的 tuple, 变成另外一种形式的 tuple。如果对物化进行延迟的话,可以减少物化的开销(因为要物化的字段少了),甚至直接不需要物化

  • 如果数据是被压缩过的,物化的过程就必须对数据进行解压,这会影响压缩带来的好处

  • 列式的内存组织形式对 CPU Cache 非常友好,从而提高计算效率,相反行式的内存组织形式因为非必要的列占用了 Cache Line 的空间,Cache 效率低

  • 块遍历的优化手段对 Column 类型的数据效果更好,因为数据以 Column 形式保存在一起,数据是定长的可能性更大。而如果 Row 形式保存在一起数据是定长的可能性非常小(因为你一行数据里面只要有一个是非定长的,比如 VARCHAR,那么整行数据都是非定长的)

延迟物化的缺点

延迟物化且多表 Join 连接后, 许多 Join Algorithms 会对左(外)侧输入位置关系排序,右(内)侧输出位置不会排序(准确的说至少有一侧不会被排序),因为以这种无序的方式从列中提取值需要为每个位置跳转存储, 产生了随机访问,相比顺序访问会产生较大的开销。

对左(外)侧输入位置关系排序也有例外:对两组输入进行排序或重新分区的 Join 算法,不会对左右位置列表进行排序。但无论哪种方式,至少有一组输出位置不会被排序。

从下图可以看出延迟物化在列式数据库优化中可以带来巨大的收益

表连接

6.1 更加有效地表连接

Hash-join

  • 以 Hash-join (散列连接,典型连接算法) 为例,column store 可以让 probe 探测表更紧凑(会产生更紧凑的散列表,从而在探测期间 during probing 产生更好的访问模式)

  • a smaller hash table leads to less cache misses 更小的散列表导致了更少的缓冲区丢失

 

Jive-Join

Jive-Join (两次排序) 解决 Unordered positional lookups。基本思想是在我们想要提取的位置列表中添加一个额外的列,这是一个密集有序递增的整数序列。

Invisible Join

在延迟物化缺点部分提到,Join 后,许多 Join Algorithms 会对左(外)侧输入位置关系排序,右(内)侧输出位置不会排序,这是因为左列中的位置通常按顺序迭代,而右列中的位置会被探测以查找连接谓词匹配项。因此需要添加一个排序列。

为了解决这个问题,又提出了一个新的 Join 算法:Invisible Join 隐式连接。

更多 Join 实现

当然还有 BroadcastJoin,LookupJoin,SortJoin...

6.2 Jive-Join

对于 Join 而言,运算的核心在于两表中 Joinkey 的匹配上。对于其他列数据匹配上了就复制,匹配不上就丢弃。结合延迟物化,匹配后再加载其他列数据,从而减小不必要的 IO。

举个例子, 如下 SQL:

SELECT emp.age, dept.name FROM emp, dept WHERE emp.dept_id = dept.id

假设原始数据值如下:

根据上面延迟物化部分我们可以已知,数据的查询过程中,我们先抽出 emp 表的 dept_id 和 dept 表的 id 列数据,进行匹配;并输出匹配结果对应原表的位置信息。(黄色文字部分是指 position 指向的值, 在实际 Join 中不会出现)

会得到如下的数据:

然后根据输出的位置信息,就可以从原始数据中抽取 age、name 列的数据得到 Join 最后的结果。

由于上图右侧输出无序,如果回表查必然造成大量随机 IO ,为了解决这个问题,Jive Join[参考文献 Fast Joins Using Join Indices]采用了对其进行排序之后再查询,即将随机 IO 转化为顺序 IO 的方法进行优化。

实现方式为:在右侧表 position 列上添加一个额外的列(一个密集递增的整数序列)。

排序输出:

最后,为了保持原 SQL 语义的一致性,我们对数据结构再次排序,这次是按最初添加到连接输出的列,将当前数据结构恢复为原始连接顺序(以便与另一个表的连接输出相匹配):

6.3 Jive-Join 进一步的优化思路

  • 不需要完全排序整个列数据, 来减少 join 值中列输出的随机访问性能开销

  • 存储介质被分成连续的存储块,块内的随机访问比跨块的随机访问代价小得多

  • 因此,只需要在存储(或其近似值)上划分为可以找到这些位置的块。在每个分区内,位置可以保持无序,因为存储块内的随机访问要便宜得多

  • 保证块维度的顺序访问,块内的数据可以保持无序,来替代全局列按精确的位置顺序访问。这个也就是一个新的概念: Radix Hash Join:

https://nan01ab.github.io/2019/03/Hash-Joins.html

总结

7.1 列式存储优点

数据压缩,确定一列数据的规律

  1. 查询时可以时读的数据量更少,在 IO 密集型计算中获得更多的性能优势

  2. 相同类型压缩效率更高

  3. 可以针对不同类型使用不同的压缩算法。LZ4,run-length encoding,delta encoding

  4. 高效的压缩可以减少磁盘 IO 数据量,但是高效的压缩都必须遵循某种特殊的规律,比如数据的长度,类型等一致;基于列式的查询数据库正好遵循这一点;此外,某些特别的数据压缩格式,比如 RUN-Length 编码,甚至可以在不做解压时便可以对数据过滤,减少无关的 IO

数据选择优势大

  1. 可以选择特定的列做计算而不是读所有列

  2. 对聚合计算友好

更容易向量化

  1. 向量化基于 SIMD (single instruction multiple data) 。对于现代多核 CPU,其都有能力用一条指令执行多条数据

  2. 向量化对数据格式有要求:要处理的数据需要是连续内存;需要明确数据类型

  3. 执行模型要求:数据需要按批读取;函数的调用需要明确数据类型

  4. 列存数据库本身按列存储和读取,可以保证数据按批读取,在内存中连续;可以根据列的类型定义数据读写逻辑;函数按列类型处理

更适合做延迟物化

  1. 物化: 将列数据转换为可以被计算或者输出的行数据或者内存数据结果的过程,物化后的数据通常可以用来做数据过滤,聚合计算,Join

  2. 缓存友好;节省 CPU / 内存带宽;可以利用到执行计划和算子的优化,例如 filter;可以直接在压缩列做计算

7.2 写在最后

实际上,列存数据库不只是列式存储的存储格式问题,底层存储的变化往往牵一发而动全身,如何适应性的修改计算引擎、存储引擎、存取方式等来达到更高更快的性能,并适应不同的 workload 或者硬件发展的趋势,都是基于列式存储数据库要关心的问题。

相关文章:

干货分享,现代列式数据库系统如何设计与实现? | StoneData 论文选读

作者&#xff1a;袁洋 | StoneData 技术架构师 审核&#xff1a;王博 论文链接&#xff1a;columnstoresfntdbs.pdf (harvard.edu) 列存四先驱和 MIT 知名教授 Samuel Madden 于 2013 年在某期刊上写的一篇当时列存相关技术的综述。文章还挺全面也很经典&#xff0c;通过剖析三…...

说说构建流批一体准实时数仓

分析&回答 基于 Hive 的离线数仓往往是企业大数据生产系统中不可缺少的一环。Hive 数仓有很高的成熟度和稳定性&#xff0c;但由于它是离线的&#xff0c;延时很大。在一些对延时要求比较高的场景&#xff0c;需要另外搭建基于 Flink 的实时数仓&#xff0c;将链路延时降低…...

北京筑龙受邀出席中物联“采购供应链中国行—走进雄安”活动

日前&#xff0c;“采购供应链中国行—走进雄安”活动在河北雄安新区成功举办&#xff0c;来自30家相关单位的50余名领导和代表参加了本次活动。活动由中国物流与采购联合会公共采购分会主办&#xff0c;中国物流与采购联合会采购委、中国雄安集团有限公司、河北雄安新区招标投…...

【Tkinter界面:练习-01】窗口-部件-布局

一、说明 python在用户界面开发中&#xff0c;其中有QT5&#xff0c;和Tkinter&#xff1b;对于实际项目&#xff0c;界面需要高大上&#xff0c;因此用QT5&#xff0c;对于开发人员的演示程序&#xff0c;或简单程序中&#xff0c;不建议QT5&#xff1b;用Tkinter已经足够。本…...

LeetCode每日一题:823. 带因子的二叉树(2023.8.29 C++)

目录 823. 带因子的二叉树 题目描述&#xff1a; 实现代码与解析&#xff1a; dp hash 原理思路&#xff1a; 823. 带因子的二叉树 题目描述&#xff1a; 给出一个含有不重复整数元素的数组 arr &#xff0c;每个整数 arr[i] 均大于 1。 用这些整数来构建二叉树&#x…...

【教学类-35-01】学号+姓名+班级(描字帖)A4一页

背景说明&#xff1a; 本学期我带机动班&#xff0c;其中大4班去的频率比较高&#xff0c;与是我用大四班的名单做了一份 “描字帖”&#xff0c;在9月1日第一天见面时&#xff0c;孩子们用记号笔描字帖时&#xff0c;我也可以对这些孩子初步混个眼熟&#xff08;聪明的&#x…...

UE5 里的一些常用的了解

# ACharacter、APawn的继承关系 ACharacter -继承自-> APawn -继承自-> AActor和 INavAgentInterface AActor -继承自-> UObject -继承自->UObjectBaseUtility -继承自-> UObjectBase&#xff08;一个独立的类&#xff09;INavAgentInterface是一个独立的类 #…...

【网络安全带你练爬虫-100练】第19练:使用python打开exe文件

目录 一、目标1&#xff1a;调用exe文件 二、目标2&#xff1a;调用exe打开文件 一、目标1&#xff1a;调用exe文件 1、subprocess 模块允许在 Python 中启动一个新的进程&#xff0c;并与其进行交互 2、subprocess.run() 函数来启动exe文件 3、subprocess.run(["文件路…...

【2D/3D RRT* 算法】使用快速探索随机树进行最佳路径规划(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

用反射实现自定义Java对象转化为json工具类

传入一个object类型的对象获取该对象的class类getFields方法获取该类的所有属性对属性进行遍历&#xff0c;并且拼接成Json格式的字符串&#xff0c;注意&#xff1a;通过属性名来推断方法名获取Method实例通过invoke方法调用 public static String objectToJsonUtil(Object o…...

rk3568 nvme硬盘分区,格式化,挂载测试

前言 环境介绍&#xff1a; 1.编译环境 Ubuntu 18.04.5 LTS 2.SDK rk356x_linux 3.单板 迅为itop-3568开发板 自制底板 一、查看硬盘 插上硬盘上电&#xff0c;进入系统后通过命令lspci查看nvme硬盘识别情况 [rootRK356X:/]# lspci -k 21:00.0 Class 0108: 1e4b:1202…...

Failed to load ApplicationContext解决办法,spring版本问题

有如下报错&#xff1a; "D:\Program Files\Java\jdk-13.0.1\bin\java.exe" -agentlib:jdwptransportdt_socket,address127.0.0.1:7325,suspendy,servern -ea -Didea.test.cyclic.buffer.size1048576 -Dfile.encodingUTF-8 -classpath "D:\Program Files\JetBr…...

Is f(z)=1/z truly an analytic function

https://math.stackexchange.com/questions/755566/is-fz-1-z-truly-an-analytic-function...

代理模式 静态代理和动态代理(jdk、cglib)——Java入职第十一天

一、代理模式 一个类代表另一个类去完成扩展功能,在主体类的基础上,新增一个代理类,扩展主体类功能,不影响主体,完成额外功能。比如买车票,可以去代理点买,不用去火车站,主要包括静态代理和动态代理两种模式。 代理类中包含了主体类 二、静态代理 无法根据业务扩展,…...

Remmina在ubuntu22.04中无法连接Windows

Remmina在ubuntu22.04中无法连接Windows 问题 提示为&#xff1a; 无法通过TLS到RDP服务器… 分析 原因是Remmina需要使用openssl通过RDP加密与Windows计算机连接&#xff0c;而ubuntu22.04系统中OpenSSL版本为3.0&#xff0c;Openssl3 将 tls<1.2 和 sha1 的默认安全级别…...

【uniapp】this有时为啥打印的是undefined?(箭头函数修改this)

&#x1f609;博主&#xff1a;初映CY的前说(前端领域) ,&#x1f4d2;本文核心&#xff1a;uniapp中this指向问题 前言&#xff1a;this大家知道是我们当前项目的实例&#xff0c;我们可以在这个this上面拿到我们原型上的全部数据。这个常用在我们在方法中调用其他方法使用。 …...

2023高教社杯数学建模思路 - 复盘:光照强度计算的优化模型

文章目录 0 赛题思路1 问题要求2 假设约定3 符号约定4 建立模型5 模型求解6 实现代码 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 问题要求 现在已知一个教室长为15米&#xff0c;宽为12米&…...

河道漂浮物检测:安防监控/视频智能分析/AI算法智能分析技术如何助力河道整治工作?

随着社会的发展和人们生活水平的进步&#xff0c;水污染问题也越来越严重&#xff0c;水资源监管和治理成为城市发展的一大困扰&#xff0c;水面上的漂浮垃圾不仅会影响河道生态安全并阻碍船舶航行&#xff0c;还会影响人们的身体健康。 TSINGSEEE青犀AI智能分析平台在环保场景…...

Dubbo 应用切换 ZooKeeper 注册中心实例,流量无损迁移

首先思考一个问题&#xff1a;如果 Dubbo 应用使用 ZooKeeper 作为注册中心&#xff0c;现在需要切换到新的 ZooKeeper 实例&#xff0c;如何做到流量无损&#xff1f; 本文提供解决这个问题的一种方案。 场景 有两个基于 Dubbo 的微服务应用&#xff0c;一个是服务提供者&…...

ADB入门教程

安卓开发 文章目录 安卓开发前言USB 连接链接 前言 基本用法 命令语法 adb 命令的基本语法如下&#xff1a; adb [-d|-e|-s <serialNumber>] <command>如果只有一个设备/模拟器连接时&#xff0c;可以省略掉 [-d|-e|-s ] 这一部分&#xff0c;直接使用 adb 。 为…...

SQLPro Studio for Mac:强大的SQL开发和管理工具

SQLPro Studio for Mac是一款强大的Mac上使用的SQL开发和管理工具&#xff0c;它支持各种数据库&#xff0c;包括MySQL&#xff0c;PostgreSQL&#xff0c;SQLite等。使用 SQLPro Studio&#xff0c;您可以轻松地连接和管理您的数据库&#xff0c;执行SQL查询和脚本&#xff0c…...

淘宝API技术解析,实现按图搜索淘宝商品

淘宝提供了开放平台接口&#xff08;API&#xff09;来实现按图搜索淘宝商品的功能。您可以通过以下步骤来实现&#xff1a; 1. 获取开放平台的访问权限&#xff1a;首先&#xff0c;您需要在淘宝开放平台创建一个应用&#xff0c;获取访问淘宝API的权限。具体的申请步骤和要求…...

错误:依赖检测失败: mysql-community-libs(x86-64) >= 5.7.9 被 (已安裝) mysql-community-li

错误&#xff1a; 错误原因&#xff1a;没有删除之前安装的依赖问题 解决办法&#xff1a; yum remove mysql-libs 再用下面指令检查一遍&#xff1a; rpm -qa | grep mysql 如果有还未清理的&#xff0c;用下面指令&#xff1a; rpm -e xxx...

使用MATLAB解算炼油厂的选址

背景 记得有一年的数据建模大赛&#xff0c;试题是炼油厂的选址&#xff0c;最后我们采用MATLAB编写&#xff08;复制&#xff09;蒙特卡洛算法&#xff0c;还到了省级一等奖&#xff0c;这里把仅有一些记忆和材料&#xff0c;放到这里来&#xff0c;用来纪念消失的青春。 本…...

AudioTrack播放音乐之getMinBufferSize

1. AudioTrack播放音乐之前需要做好准备,即需要先计算最小音频数据缓存空间 文件路径:AudioTrack.java (frameworks\base\media\java\android\media) static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {@参数sampleRateInHz,…...

React和Redux中的不变性

https://overreacted.io/zh-hans/a-complete-guide-to-useeffect/ 一、不变性和副作用 1.不变&#xff1a;不断创造新值来替换旧值 2.不变性规则&#xff1a; &#xff08;1&#xff09;当给定相同的输入时&#xff0c;纯函数必须始终返回相同的值 &#xff08;2&#xff0…...

NPM 常用命令(一)

目录 1、npm 1.1 简介 1.2 依赖性 1.3 安装方式 2、npm access 2.1 命令描述 2.2 详情 3、npm adduser 3.1 描述 4、npm audit 4.1 简介 4.2 审计签名 4.3 操作示例 4.4 配置 audit-level dry-run force json package-lock-only omit foreground-scripts …...

【ES6】Promise推荐用法

一般来说&#xff0c;不要在then()方法里面定义 Reject 状态的回调函数&#xff08;即then的第二个参数&#xff09;&#xff0c;总是使用catch方法。 // bad promise.then(function(data) {// success}, function(err) {// error});// good promise.then(function(data) { //…...

【JavaScript】版本判断

用于客户端和服务端进行版本更新判断使用&#xff0c;如有BUG&#xff0c;还望指出 效果 console.log(isAllowUpdate(1,2.0.0), // trueisAllowUpdate(2.0,2.0.0), // falseisAllowUpdate(2.0,2.0.1), // trueisAllowUpdate(2.1.1,2.1.2), // trueisAllowUpdate(2.1.3,2.1.2),…...

Nano编辑器安装使用指南

关于nano Nano编辑器是一个命令行文本编辑器&#xff0c;具有简单易用的界面和一些基本功能。 Nano小巧友好&#xff0c;提供许多额外的特性&#xff0c;例如交互式的查找和替换、定位到指定的行列、自动缩进、特性切换、国际化支持、文件名标记完成等。 Nano是为了代替闭源的…...