【InnoDB数据存储结构】第2章节:InnoDB行格式

news2024/9/20 18:51:46

目录结构

之前整篇文章太长,阅读体验不好,将其拆分为几个子篇章。

本篇章讲解 InnoDB 行格式。

InnoDB 行格式

InnoDB 一行记录是如何存储的?

这个问题是本文的重点,也是面试中经常问到的问题,所以就引出了下文的 InnoDB 行格式内容。

InnoDB 指定行格式语法

先看下指定行格式的简单语法

#创建表指定行格式
create table table_name(列信息) row_format = 行格式名称

#修改表行格式
alter table table_name row_format = 行格式名称

Compact 行格式

Compact 行数据存储结构

在 MySQL5.1 版本中,默认设置为 Compact 行格式。一条完整的记录其实可以被分为记录的额外信息和记录的真实数据两大部分。

**举例:**采用 Compact 行格式创建一张表 page_demo

create table page_demo (
  c1 int,
  c2 int,
  c3 varchar(10000),
  primary key(c1)
) CAHRSET=ascii ROW_FORMAT=Compact
  • 字符集:ascii
  • 行格式:Compact

表中的每一行记录的行格式如下所示:

这些记录头信息中的各个属性如下(主要 6 个属性):

其中有两个预留位置没有使用,我们简化之后的行格式如下所示:

向库中插入 4 条数据:

insert into page_demo 
values
(1, 100, 'song'),
(2, 200, 'tong'),
(3, 300, 'zhan'),
(4, 400, 'lisi');

这 4 条记录的行格式如下所示:

上图各方块属性:

  • 蓝色方块为记录头信息
  • 绿色方块为 数据信息,这里为了展示方便,写的是 10 进制 ,实际上底层存储的是 2 进制

变长字段长度列表

创建一张表 record_test_table

create table record_test_table(
  col1 varchar(8),
  col2 varchar(8) not null,
  col3 vhar(8),
  col4 varchar(8)
) charset=ascii row_format=Compact

向表里面插入两个数据:

insert into record_test_table(col1, col2, col3, col4)
values
('zhangsan', 'lisi', 'wangwu', 'songhk'),
('tong', 'chen', NULL, NULL);

MySQL 支持一些变成的数据类型,比如 varchar(M)、varbinary(M)、text、blob 等类型,这些数据类型修饰的列被称为 变成字段。边长字段中存储多少个字节的数据是不固定的,所以我们在存储真实数据的时候需要顺便把这些数据占用的字节数也存储起来。

在 Compact 行格式中,把所有变长字段的真实数据占用的字节长度存放在记录的开头部位,从而形成一个变长字段长度列表。

注意:

这里存储的变长字段的长度的顺序和表字段创建时的真实顺序是翻过来的,比如:两个 varchar 字段在表中的顺序是 a(10),b(15)。那么在变长字段长度列表中的顺序是 15,10,翻过来存储的。

根据上面插入的两条真实数据,分析一下各个变长字段真实数据占用的字节长度:

NULL 值列表

Compact 行格式会把可以为 NULL 值的列统一管理起来,存在一个标记为 NULL 值列表中。

如果表中没有可以为 NULL 值的列,那这个 NULL 值列表也就不存在。

为什么要定义 NULL 值列表?

之所以要存储 NULL值,是因为数据都是需要对齐的。如果没有标注出 NULL 值的位置,就有可能在查询数据的时候出现混乱 的情况。如果 使用一个特殊符号代替 NULL 值放到对应的位置,虽然可以达到效果,但是大量为 NULL 值的列会严重 浪费空间,所以直接在 行数据的头部开辟出一块空间 专门用来存储该行数据有哪些是非空数据,哪些是空数据, 格式如下:

  • 二进制位为 1:代表列值为 NULL
  • 二进制为为 0:代表列值不为 NULL

这样我们回答一个问题,MySQL 中的 NULL 值是怎么存储的?

答:NULL 值是由 NULL 列表记录的,用二进制逆序表示每一行记录中的每一列是否为 NULL 值,0 代表不为 NULL,1 代表为 NULL 值。

假设有一张表有 4 个字段,col1、col2、col3、col4

插入一条记录:‘a’, NULL, NULL, ‘dd’

那 NULL 值列表用二进制表示为:0 1 1 0,转化为 10 进制就是 06。

记录头信息(5 字节)

delete_mask(删除标记)

这个属性标记着当前记录是否被删除,占用 1 个 bit:

  • 值为 0:代表记录没有被删除
  • 值为 1:代表记录被删除了

被删除的记录为什么还在页中存储?

这些被删除的记录之所以不立即从磁盘的页中移除,是因为移除他们之后,紧跟着他们的记录需要 重新排列,特别是对 聚簇索引的叶子节点,假设移除的是主键值为 1的记录, 那整个聚簇索引的叶子节点会因为这一条记录的删除全部重新排序,导致性能消耗。所以只是将这些删除的记录做一个删除标记和正常记录做个区分,实际上这些被删除的记录会组成一个 垃圾链表,它们所占用的空间被称为 可重用空间,之后再插入的数据,可能会把这些被删除记录占用的空间直接 覆盖掉(复用)

min_rec_mask(最小记录标记)

B+Tree 的每层非叶子节点中的最小记录都会添加该标记,并且 min_rec_mask的值为 1。

我们自己插入的数据记录的 min_rec_mask的值为 0,所以它们都不是 B+Tree 的非叶子节点中的最小记录(这句话自己理解就行,不要纠结)。

record_type(记录类型)

这个属性代表当前记录的类型,一共有 4 种类型的记录:

  • 0:表示普通记录
  • 1:表示 B+Tree 非叶子节点记录
  • 2:表示最小记录
  • 3:表示最大记录

从图中可以看出,我们自己插入的记录的 record_type的值为 0,最大最小记录的 record_type的值分别为 23

非叶子节点记录 record_type的值为 1的情况(索引的数据结构一文中讲述的内容):

heap_no(记录位置)

这个属性代表代表当前记录在当前页中的下标位置。

下标为 0、1 的两条记录分别为最大和最小记录,在上文【Infimum + Supremum(最大记录和最小记录)】中已经提到了,因为这两个记录不是我们插入的,所以有时候也称为 伪记录虚拟记录

n_owned(每组记录数)

页目录(有多个组)中每个组中最后一条记录的头信息中会存储该组一共有多少条记录,作为 n_owned字段的值。

next_record(下一条记录的地址偏移量,非指针)

记录头中该属性非常重要,它表示从 当前记录的真实数据下一条记录的真实数据 之间的 地址偏移量

比如:第一条记录中的 next_record值为 32,意味着从第一条记录的真实数据的地址处向后找 32 个字节,便是下一条记录的真实数据。

**注意:**下一记录并不是按照我们插入顺序的下一条记录,而是按照主键值顺序排列的下一条记录。

InnoDB 底层规定 Infimum 记录(最小记录)的下一条记录就是当前页中主键值最小的记录,而当前页中主键值最大的记录指向的下一条记录就是 Supremum 记录(最大记录)

下图用箭头指向代替地址偏移量,来表示 next_record

演示:删除一条记录的操作

根据上图所示,假设删除上图第 2 条记录:

# 删除主键值为2的记录
delete from page_demo where c1 = 2;

删除之后,整个链表也会跟着变化,第一条记录的 next_record就会直接指向第 3 条记录,但是第 2 条记录并没有被真实删除,只是将 delete_mask值变成了 1。下图所示:

变化内容如下:

  • 第 2 条记录的 delete_mask变为 1

  • 第 2 条记录的 next_record变为 0,代表不再指向真实数据了

  • 最大记录的 n_owned的值从 5=> 4,因为当前组少了一条记录

    • 原本当期页算上最大最小记录,总共 6 条记录,分为两个组,最小记录为一个组
    • 四条真实记录和最大记录为一组,所以最大记录中的n_owned的值为 5
    • 现在第二组中删除了一条记录,所以n_owned的值从 5=> 4

演示:增加一条记录的操作

上述主键值为 2 的记录被删除后(变成了垃圾链表),但是存储空间并没有被收回,如果再次把这条记录插入表中,会发生什么?

insert into page_demo values(2, 200, 'tong');

如下图所示:

变化内容如下:

  • 新插入的数据,因为指定了主键值为 2,所以按照聚簇索引结构这条记录会按照顺序插入原来第 2 条记录的位置
  • 因为原来被删除的第 2 条记录并没有被真实删除,仍然占有空间,所以这次新插入的数据会复用原有的空间
  • 第 2 条记录的 delete_mask的值变为 0
  • 第 2 条记录的 next_record的值变为 32
  • 第 1 条记录的 next_record指向第 2 条记录,第 2 条记录的next_record指向第 3 条记录
  • 最大记录的 n_owned的值从 4 => 5

记录的真实数据

记录的真实数据,除了我们自定义的列的数据以外,还会有三个隐藏列:

实际上这几个列的真实名称是:

  • db_row_id
  • db_trx_id
  • db_roll_ptr

其中 row_id 字段的含义,如果一个表没有手动定义主键,则会选取一个 Unique 键(值唯一的列)作为主键,如果连 Unique 键都没有定义的话,则会为表默认添加一个名为 row_id 的隐藏列作为主键。所以 row_id 是在没有手动定义主键以及不存在 Unique 键的情况下才会存在。

transaction_id 和 roll_pointer 涉及到事务,后面学到再讲解。

举例:创建一张表 mytest

create table mytest(
  col1 varchar(10),
  col2 varchar(10),
  col3 char(10),
  col4 varchar(10)
)engine=innodb charset=latin1 row_format=compact

插入三条数据:

insert into mytest values
('a', 'bb', 'bb', 'ccc'),
('d', 'ee', 'ee', 'fff'),
('d', NULL, NULL, 'fff');

找到存储表文件 mytest.ibd 的位置,用 notepad++打开,

刚打开可能会乱码,可以安装一个解析插件(自行解决),解析为十进制的数据格式。

格式化之后,二进制文件如下,只需要看真实数据存储的二进制即可:

我们对照下插入的三行记录:

('a', 'bb', 'bb', 'ccc'),
('d', 'ee', 'ee', 'fff'),
('d', NULL, NULL, 'fff');

解析上面的二进制文件,因为 col3 列是定长,不计入变长字段列表,下面解析第一行记录:

  • 【变长字段区域】:03 02 01 对照 col3 列 ccc 长度为 03,col2 列 bb 长度为 02,col1 列 a 长度为 01
  • 【NULL 值列表区域】:00 代表都是非空的字段,实际上是按照字段的逆序组成的二进制 0 0 0 0 ,转化为十进制就是 00
  • 【记录头信息】:00 00 10 00 2c 对照记录头信息(5 个字节),其中 2c对应 next_record,偏移 2c 个字节到下一条记录的位置
  • 【row_id】:00 00 00 2b 68 00 对照隐藏主键(6 字节),当没有手动指定主键,且没有 Unique 建时,InnoDB 会默认创建 row_id
  • 【transaction_id】:00 00 00 00 06 05 对照事务id(6 字节)
  • 【roll_pointer】:80 00 00 00 32 01 10 对照回滚指针(7 字节)
  • 【真实记录】:61 对照第一行记录 col1 的值 a
  • 【真实记录】:62 62 对照第一行记录 col2 的值 bb
  • 【真实记录】:62 62 20 20 20 20 20 20 20 20 对照第一行记录 col3 的值 bb,后面的 20 作为一个空值,因为 col3 字段是定长 char(10)10 个字节,而一个字符 b 只占 1 个字节,所以用 8 个 20 填充 8 个空字节位
  • 【真实记录】:63 63 63 对照第一行记录 col3 的值 ccc

根据上面的分析我们大致知道了,一行完整数据底层二进制文件的存储格式是怎样的。

第二行记录和第一行内容想通,根据行格式自行推断。

我们重点来看第三行记录是如何存储的?

  • 【变长字段列表】:03 01 对照字段 col4 和 col1,col3 和 col2 为 NULL 值不记录
  • 【NULL 值列表】:06 对照四个字段是否为 NULL 值的二进制 0 1 1 0,转化为十进制就是 06
  • 记录头信息】:00 00 20 ff 98 对照记录头信息(5 个字节),其中 98 是 next_record
  • 【row_id】:00 00 00 2b 68 02 对照 row_id(6 字节)
  • 【transaction_id】:00 00 00 00 06 07 对照事务 id(6 字节)
  • 【roll_pointer】:80 00 00 00 32 01 10 对照回滚指针(7 字节)
  • 【真实记录】:64 对照第三行记录的 col1 字段的值 d
  • 【真实记录】:66 66 66 对照第三行记录的 col4 字段的值 fff,因为 col2 和 col3 都是 NULL值所以没有记录

到这我们就分析完了,应该对底层二进制文件的存储有了一定的认知吧。

Dynamic 和 Compressed 行格式

字段的长度限制

在了解行溢出之前我们要先了解下一个字段的最大长度。

回顾一下,char 和 varchar 的区别

一个 varchar 类型的字段,最大容量为 65535 个字节。

我们创建一张表,验证一下是否真的可以指定为 65535 个字节?

首先我们查看一下 MySQL8.0.26 默认字符集

说明默认字符集采用 utf8mb4

再查看一下 MySQL5.7.34 默认字符集

说明默认字符集采用 utf8

这里我们统一采用 8.0.26 版本去实践验证。

首先我们明确一点,不同字符集字符和字节的对等关系:

  • **utf8 字符集:**1 个字符等于 3 个字节
  • **utf8mb4 字符集:**1 个字符等于 4 个字节
  • **ascii 字符集:**1 个字符等于 1个字节

第一步我们采用默认字符集创建一张表 varchar_size_demo,行格式统一采用 Compact

  • **utf8mb4 字符集:**1 个字符等于 4 个字节
create table varchar_size_demo  (
  c varchar(65535)
) row_format=COMPACT;

报错提示,字段长度最大不能超过 16383,因为 8.0.26 版本默认字符集为utf8mb4,也就是一个字符等于 4 个字节,但是16383 * 4 = 6553265532 还差了 3 个字节到 65535,按理论我们应该用 65535 除以 4 等于 16383.75,但是字段长度不能带小数,那我们字舍五入将字段长度改为 16384再试下:

显示还是不能超过 16383,那我们将字段长度改为 16383,再次尝试:

创建成功!!!

思考一下,那 3 个字节跑哪去了?

16383 * 4 = 65532

65535 - 65532 = 3

原因是:每一行记录的头信息中都会默认有 变长字段长度列表(2 字节)NULL 值列表 (1 字节),所以每一行记录都会默认空出 3 个字节,用户存储变长字段和 NULL 值的标识。

上述我们采用的是 8.0.26 默认的字符集 utf8mb4,下面我们验证一下指定字符集采用 utf8。

  • **utf8 字符集:**1 个字符等于 3 个字节

根据上述所知要预留 3 个字节,65535 - 3 = 6553265532 / 3 = 21844

也就是说字符集 utf8 字段的最大长度限制为 21844

那我们假设长度为 21845,创建表 varchar_size_demo1

-- utf8字符集,1个字符等于3个字节
create table varchar_size_demo1 (
  c varchar(21845)
)charset=utf8;

创建报错,显示字段过长。

那我们指定字段长度为 21884再次创建:

-- utf8字符集,1个字符等于3个字节
CREATE TABLE varchar_size_demo1 (
  c VARCHAR(21844)
)CHARSET=utf8;

创建成功,那就说明我们上述的逻辑是对的。

再指定字符集为 ASCII创建表 varchar_size_demo2

  • **ascii 字符集:**1 个字符等于 1个字节

预留 3 个自己,那字段长度最大为 65532,如果指定长度为 65533看下效果:

-- ascii字符集,1个字符等于1个字节
create table varchar_size_demo2 (
  c varchar(65533)
)charset=ascii;

创建失败,将字段长度改为 65532再次创建:

-- ascii字符集,1个字符等于1个字节
create table varchar_size_demo2 (
  c varchar(65532)
)charset=ascii;

OK 创建成功,撒花!!!

行溢出

根据上文所说的单个字段的最大长度根据不同的字符集,会有不同的限制,8.0.26 默认采用 utf8mb4字符集

  • **utf8mb4 字符集:**1 个字符等于 4 个字节

varchar 类型最大为 65535 个字节,预留 3 个字节,一个 varchar 字段最大的容量为 65533 字节,而 InnoDB 的一个数据页的大小为 16KB,16 * 1024 = 16384个字节,一个 varchar 的容量远远大于一个数据页的大小,这样就可能出现一个页存不下一行记录,这种现象成为 行溢出

在 Compact 和 Redundant 行格式中,对于占用存储空间非常大的列,在记录的真实数据处只会存储该列的一部分数据(768 个前缀字节),把剩余的数据分散存储在其他的页中,这叫作 分页存储

然后记录的真实数据处用 20 个字节存储指向这些分散页的地址(这 20 个字节中还包括存储了分散在各个页中的真实数据占用的字节数),从而可以找打剩余数据所在的页,这称为页的扩展,如下图所示:

Dynamic 和 Compressed 行格式

在 MySQL8.0 中,默认的行格式为 Dynamic,Dynamic 和 Compressed 这两种行格式和 Compact 行格式类似,只不过在处理行溢出数据时方式不同,区别如下:

  • Compact 和 Redundant 两种行格式会在记录的真实数据处存储一部分数据(768 个前缀字节)。
  • Dynamic 和 Compressed 两种行格式对于存放在 Blob 中的数据采用了完全的行溢出存储方式。如下图所示,如果一行记录数据溢出了,在数据页中只存储 20 个字节的指针地址(存储真实数据的溢出页的地址),实际的数据都存储在 Off Page(溢出页)中。

Compressed 和 Dynamic 是什么区别呢?

Compressed 是在 Dynamic 的基础上优化了一层,存储在其中的行数据会以 zlib 算法进行压缩存储,因此对于 Blob、Text、Varchar 这类大长度类型的数据能够进行非常有效的存储。

Redundant 行格式

Redundant 是 MySQL5.0 版本之前 InnoDB 的行记录存储格式,MySQL 5.0 支持 Redundant 是为了兼容之前版本的页格式。

比如直接修改表的行格式为 Redundant:

alter table record_test_table row_rormat=Redundant;

Redundant 行格式存储格式如下所示:

对比 Compact 行格式主要有两大处不同:

  • Compact 是 变长字段长度 列表,Redundant 是 字段长度偏移 列表
  • Compact 有 NULL 值列表,Redundant 没有 NULL 值列表

字段长度偏移列表

为什么说 Redundant 行格式会有冗余说法?

因为 Redundant 行格式的字段长度便宜列表会将该行记录中所有列(包括隐藏列)的长度信息都按照逆序存储起来。

偏移 两字,意味着 Redundant 行格式计算列值的长度的方式不想 Compact 行格式那么直观,它是采用两个相邻数值的差值来计算各个列值的长度。

比如第一行记录的字段长度偏移列表(逆序)是:

  • 2B 25 1F 1B 13 0C 06

因为它是按照逆序排列的,所以按照顺序排列就是:

  • 06 0C 13 1B 1F 25 2B

可以看出有三个隐藏列和四个字段列。

按照两个相邻数值的差值来计算各个字段列值的长度的如下表所示:

列名十六进制字节数十进制字节数
row_id0x066
transaction_id0x0C - 0x066
roll_pointer0x13 - 0x0C7
col10x1B - 0x138
col20x1F - 0x1B4
col30x25 - 0x1F6
col40x2B - 0x256

记录头信息(record header)

不同于 Compact 行格式,Redundant 行格式中的记录头信息固定占用 6 个字节(48 位),每位的含义如下:

与 Compact 行格式的记录头信息对比来看,有两处不同:

  • Redundant 行格式多了 n_field1byte_offs_flag这两个属性
  • Redundant 行格式没有 record_type这个属性

其中两个属性的含义:

  • n_field代表一行中列的数量,占用 10 位,所以 MySQL5.0 之前的版本最多只能包含 1023 个列。

  • 1byte_offs_flags该属性定义了字段长度偏移列表占用 1 个字节,还是 2 个字节。

    • 当值为 1 时,表示占用 1 个字节;
    • 当值为 2 时,表示占用 2 个字节。

小结

到这我们就把 MySQL 的行格式了解的差不多了,当然更底层的知识点我们也用不到,也不会去用它,了解到这个层面其实在工作中也已经足够用了。

本文内容总结借鉴于康师傅的 MySQL 视频课:https://www.bilibili.com/video/BV1iq4y1u7vj


在这里插入图片描述

一起学编程,让生活更随和!

如果你觉得是个同道中人,欢迎关注博主gzh:【随和的皮蛋桑】。

专注于Java基础、进阶、面试以及计算机基础知识分享🐳。偶尔认知思考、日常水文🐌。

在这里插入图片描述


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

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

相关文章

水面漂浮物监测识别摄像机

水面漂浮物监测识别摄像机是一种用于监测水体表面上漂浮物的高科技设备。它主要通过安装在水域周边的摄像头实时捕捉水面情况,利用图像识别技术自动识别和监测水面漂浮物。这种设备在环境保护、水域清洁和水质监测等方面具有广泛的应用价值。 水面漂浮物包括各类垃圾…

vc2017编译从github网站上下载的源码

以ZLmediakit为例 1.下载软件 cmakehttps://github.com/Kitware/CMake/releases/download/v3.20.5/cmake-3.20.5-windows-x86_64.zip Microsoft Visual Studio https://my.visualstudio.com/Downloads?qvisual%20studio%202017&wt.mc_ido~msft~vscom~older-downloads …

一文搞懂SiLM824x系列SiLM8243BBCL-DG 双通道死区可编程隔离驱动 主要特性与应用 让技术变得更有价值

SiLM824x系列SiLM8243BBCL-DG是一款具有不同配置的隔离双通道门极驱动器。SiLM8243BBCL-DG配置为高、低边驱动,SiLM8243BBCL-DG可提供4A的输出源电流和6A的灌电流能力,并且其驱动输出电压可以支持到33V。支持死区可编程,通过调整DT脚外部的电…

Ansible、Saltstack、Puppet自动化运维工具介绍

本文主要是分享介绍三款主流批量操控工具Ansible、Saltstack、Puppet主要对比区别,以及Ansible和saltstack的基础安装和使用示例,如果觉得本文对你有帮助,欢迎点赞、收藏、评论! There are many things that can not be broken&am…

LeetCode刷题---矩阵置零

解题思路: 本题要求原地置换元素 对矩阵进行第一轮遍历,使用第一行第一列来充当该行该列是否要置换为0的标记位,如果第一行或第一列本身就含有零元素,我们使用colZero和rowZero变量来对其标记。如果第i行第j列的那个元素为0&#…

互联网分布式应用之SpringDataJPA

SpringDataJPA Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机,Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. Spring整合Hibernate 2…

Spring配置文件

一: Bean标签基本配置 1:用途 用于配置对象交由Spring来创建,默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功。 2:基本属性(id) Bean实例在Spring容器中的唯一…

APK 瘦身

APK 瘦身的主要原因是考虑应用的下载转化率和留存率,应用太大了,用户可能就不下载了。再者,因为手机空间问题,用户有可能会卸载一些占用空间比较大的应用,所以,应用的大小也会影响留存率。 1 APK 的结构 …

台灯哪个品牌比较护眼?2024学生考研台灯推荐

在近几年,儿童青少年近视率非常高。很多家长认为孩子近视的原因是没有养成正确的用眼习惯,例如经常趴桌子写作业、眯眼看书等,但实际上这些坏习惯是因为没有合适的光线而导致的。所以安排一盏合适的台灯给孩子学习是非常重要的。但是市面上护…

Pruning Papers

[ICML 2020] Rigging the Lottery: Making All Tickets Winners 整个训练过程中mask是动态的,有drop和grow两步,drop是根据权重绝对值的大小丢弃,grow是根据剩下激活的权重中梯度绝对值生长没有先prune再finetune/retrain的两阶段过程 Laye…

el-table 展开行表格,展开的内容高度可以变化时,导致的固定列错位的问题

问题描述 一个可展开的表格(列设置了type“expand”),并且展开后的内容高度可以变化,会导致后面所有行的固定列错位,图如下,展示行中是一个树形表格,默认不展示子级,点击树形表格的…

【金猿CIO展】现代咨询CIO崔恩博:数字化转型,CIO不仅要懂技术和业务,更要“懂人”...

‍ 崔恩博 本文由现代咨询CIO崔恩博撰写并投递参与“数据猿年度金猿策划活动——2023大数据产业年度优秀CIO榜单及奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 最近几年,大数据行业的发展备受关注,尤其是2019年以后,随着企业…

异步优势演员-评论家算法 A3C

异步优势演员-评论家算法 A3C 异步优势演员-评论家算法 A3C网络结构并行步骤 异步优势演员-评论家算法 A3C A3C 在 A2C 基础上,增加了并行训练(异步)来提高效率。 网络结构 A2C: A3C: 在这两张图之间,…

Spring事务传播问题 — PROPAGATION_REQUIRES_NEW

一、描述 Spring遇到嵌套事务时,当被嵌套的事务被定义为“PROPAGATION_REQUIRES_NEW”时, 内层Service的方法被调用时,外层方法的事务被挂起; 内层事务相对于外层事务是完全独立的,有独立的隔离性等等。 二、实验 但实…

判断一个给定的数组是否是Fortran连续的np.isfortran()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 判断一个给定的数组 是否是Fortran连续的 np.isfortran() [太阳]选择题 以下代码的输出结果中正确的是? import numpy as np A np.array([[1, 2], [3, 4]]) B np.array([[1, 2], [3, 4]]…

ETLCloud X 明道云实现无缝数据连接

明道云作为一款云端协作工具,为企业提供高效的沟通、协作和数据分析服务。它可以实现企业内部沟通和协作的高效性和一体化,并提供数据分析功能,让企业能够更好地理解业务和决策。 一、传统方式同步数据的痛点 传统方式同步数据需要手动进行…

Navicat(数据库可视化软件)安装教程以及连接MYSQL

Navicat安装教程以及连接MYSQL Navicat(数据库可视化软件)安装流程安装MySQLnavicat连接mysql数据库 Navicat(数据库可视化软件) Navicat 是一款专门为 MySQL 设计的可视化数据库 GUI 管理工具,我们可以在自己的计算机…

网络安全—部署CA证书服务器

文章目录 网络拓扑安装步骤安装证书系统安装从属证书服务器 申请与颁发申请证书CA颁发证书 使用windows Server 2003环境 网络拓扑 两台服务器在同一网段即可,即能够互相ping通。 安装步骤 安装证书系统 首先我们对计算机名进行确认,安装了证书系统后我…

低代码平台开发 - 编辑器拓展

设计器(编辑器)这边内容比较杂,我们这次挑两个讲,一个是自定义出码,一个是新版本引擎中 array-setter 存在的问题这期和之前的文章关联性不大,可以直接在阿里的低代码引擎初始化的目录下进行,如…

实现文本 内容展开 / 收起

<template><el-table :data"tableData" style"width: 100%" height"250"><el-table-columnfixedprop"date"label"日期"width"150"></el-table-column><el-table-columnprop"name…