MYSQL基础架构、执行过程分析、事务的实现、索引的选择、覆盖索引

本文是mysql45讲的1-5的总结

文章目录

  • 基础架构
    • 连接器
    • 分析器
    • 优化器
    • 执行器
    • SQL查询执行过程
      • 详细执行步骤
    • SQL更新执行过程
    • 重要的日志模块:redo log
    • 重要的日志模块:binlog
      • 阶段性提交
  • 事务
    • 事务隔离的实现
    • 启动
  • 索引
    • 数据库索引模型
    • InnoDB索引组织结构
    • 主键选择
    • B+树维护操作
    • 索引重建问题
  • 覆盖索引
    • 最左前缀原则
    • 索引下推
      • 策略选择和权衡
      • 建议

基础架构

先来看一张图:

basic structure

MySQL分为Server层和存储引擎层两部分。

Server层:连接器、查询缓存、分析器、优化器、执行器等,涵盖MySQL的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。

而存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持InnoDB、MyISAM、Memory等多个存储引擎。现在最常用的存储引擎是InnoDB,它从MySQL 5.5.5版本开始成为了默认存储引擎。

不同存储引擎的表数据存取方式不同,支持的功能也不同

从图中不难看出,不同的存储引擎共用一个Server层,也就是从连接器到执行器的部分。

连接器

顾名思义就是负责跟客户端建立连接、获取权限、维持和管理连接的

我们通常命令行会这么写:

mysql -h$ip -P$port -u$user -p

用户的权限是在登录时就确认好的, 也就是说如果在登录过程中对当前用户的权限进行了修改,当前已登录用户的权限并不会发生改变,直到用户再次登录,权限才会更新

我们可以通过

show processlist

对当前链接用户进行查看

客户端如果太长时间没动静,连接器就会自动将它断开。这个时间是由参数wait_timeout控制的,默认值是8小时。

如果在连接被断开之后,客户端再次发送请求的话,就会收到一个错误提醒: Lost connection to MySQL server during query。这时候如果你要继续,就需要重连,然后再执行请求了。

数据库里面,长连接是指连接成功后,如果客户端持续有请求,则一直使用同一个连接。短连接则是指每次执行完很少的几次查询就断开连接,下次查询再重新建立一个。

建立连接的过程通常是比较复杂的,所以我建议你在使用中要尽量减少建立连接的动作,也就是尽量使用长连接。

分析器

作用:语句词法分析

语法分析器会根据语法规则,判断你输入的这个SQL语句是否满足MySQL语法。

如果你的语句不对,就会收到“You have an error in your SQL syntax”的错误提醒,比如下面这个语句select少打了开头的字母“s”。

mysql> elect * from t where ID=1;ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'elect * from t where ID=1' at line 1

优化器

在真正执行之前还需要一个优化,比如说当表里面有多个索引的时候,有多个join的时候,谁先谁后,这就是优化器要决定的事情,如何使用让效率变得更高

执行器

分析器知道了要怎么做,优化器知道了该怎么做,于是开始执行;

执行优化器选择的执行计划,与存储引擎协同工作,完成数据的实际检索和修改。

执行器会先查看是否有表读取权限,如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。

SQL查询执行过程

  • 查询示例select * from T where ID=10;
    • 输入:用户输入的SQL查询语句。
    • 输出:查询结果。

详细执行步骤

  1. SQL解析

    • 词法分析:将SQL语句分解成有意义的元素(词法单元),如关键字、标识符、常量。
    • 语法分析:根据MySQL的语法规则验证词法单元的结合是否正确。
  2. 查询优化

    • 执行计划生成:优化器评估多种可能的查询路径,生成多个执行计划。
    • 成本估算:为每个执行计划估算执行成本,选择成本最低的计划。
  3. 查询执行

    • 执行器与存储引擎交互:执行器指挥存储引擎按照优化后的计划执行查询。
    • 数据检索:存储引擎从数据文件中检索数据,返回给执行器。

    SQL更新执行过程

    更新里面其实就是查询+修改

    MySQL可以恢复到半个月内任意一秒的状态,那是怎么做到的?

    与查询流程不一样的是,更新流程还涉及两个重要的日志模块,它们正是我们今天要讨论的主角:redo log(重做日志)和 binlog(归档日志)。

    重要的日志模块:redo log

    其实就是MySQL里经常说到的WAL技术,WAL的全称是Write-Ahead Logging,它的关键点就是先写日志,再写磁盘,也就是先写粉板,等不忙的时候再写账本。

    具体来说,当有一条记录需要更新的时候,InnoDB引擎就会先把记录写到redo log(粉板)里面,并更新内存,这个时候更新就算完成了。同时,InnoDB引擎会在适当的时候,将这个操作记录更新到磁盘里面

    InnoDB的redo log是固定大小的,比如可以配置为一组4个文件,每个文件的大小是1GB,那么这块“粉板”总共就可以记录4GB的操作。从头开始写,写到末尾就又回到开头循环写,如下面这个图所示。

    redo_log

    write pos是当前记录的位置,一边写一边后移,写到第3号文件末尾后就回到0号文件开头。checkpoint是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。

    write pos和checkpoint之间的是“粉板”上还空着的部分,可以用来记录新的操作。如果write pos追上checkpoint,表示“粉板”满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把checkpoint推进一下。

    有了redo log,InnoDB就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe

    要理解crash-safe这个概念,可以想想我们前面赊账记录的例子。只要赊账记录记在了粉板上或写在了账本上,之后即使掌柜忘记了,比如突然停业几天,恢复生意后依然可以通过账本和粉板上的数据明确赊账账目。

    重要的日志模块:binlog

    Server层也有自己的日志,称为binlog(归档日志)

    因为最开始MySQL里并没有InnoDB引擎。MySQL自带的引擎是MyISAM,但是MyISAM没有crash-safe的能力,binlog日志只能用于归档。而InnoDB是另一个公司以插件形式引入MySQL的,既然只依靠binlog是没有crash-safe能力的,所以InnoDB使用另外一套日志系统——也就是redo log来实现crash-safe能力。

    这两种日志有以下三点不同。

    1. redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用。
    2. redo log是物理日志,记录的是“在某个数据页上做了什么修改”;binlog是逻辑日志,记录的是这个语句的原始逻辑,比如“给ID=2这一行的c字段加1 ”。
    3. redo log是循环写的,空间固定会用完;binlog是可以追加写入的。“追加写”是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

    更新过程

    1. 执行器先找引擎取ID=2这一行。ID是主键,引擎直接用树搜索找到这一行。如果ID=2这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。
    2. 执行器拿到引擎给的行数据,把这个值加上1,比如原来是N,现在就是N+1,得到新的一行数据,再调用引擎接口写入这行新数据。
    3. 引擎将这行新数据更新到内存中,同时将这个更新操作记录到redo log里面,此时redo log处于prepare状态。然后告知执行器执行完成了,随时可以提交事务。
    4. 执行器生成这个操作的binlog,并把binlog写入磁盘。
    5. 执行器调用引擎的提交事务接口,引擎把刚刚写入的redo log改成提交(commit)状态,更新完成。

    更新过程

    阶段性提交

    最后三步看上去有点“绕”,将redo log的写入拆成了两个步骤:prepare和commit,这就是"两阶段提交”

    binlog会记录所有的逻辑操作,并且是采用“追加写”的形式。如果你的DBA承诺说半个月内可以恢复,那么备份系统中一定会保存最近半个月的所有binlog,同时系统会定期做整库备份。这里的“定期”取决于系统的重要性,可以是一天一备,也可以是一周一备。

    当需要恢复到指定的某一秒时,比如某天下午两点发现中午十二点有一次误删表,需要找回数据,那你可以这么做:

    • 首先,找到最近的一次全量备份,如果你运气好,可能就是昨天晚上的一个备份,从这个备份恢复到临时库;
    • 然后,从备份的时间点开始,将备份的binlog依次取出来,重放到中午误删表之前的那个时刻。

    这样你的临时库就跟误删之前的线上库一样了,然后你可以把表数据从临时库取出来,按需要恢复到线上库去。

    为什么日志需要“两阶段提交”。这里不妨用反证法来进行解释。

    由于redo log和binlog是两个独立的逻辑,如果不用两阶段提交,要么就是先写完redo log再写binlog,或者采用反过来的顺序。我们看看这两种方式会有什么问题。

    仍然用前面的update语句来做例子。假设当前ID=2的行,字段c的值是0,再假设执行update语句过程中在写完第一个日志后,第二个日志还没有写完期间发生了crash,会出现什么情况呢?

    1. 先写redo log后写binlog。假设在redo log写完,binlog还没有写完的时候,MySQL进程异常重启。由于我们前面说过的,redo log写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行c的值是1。

      但是由于binlog没写完就crash了,这时候binlog里面就没有记录这个语句。因此,之后备份日志的时候,存起来的binlog里面就没有这条语句。

      然后你会发现,如果需要用这个binlog来恢复临时库的话,由于这个语句的binlog丢失,这个临时库就会少了这一次更新,恢复出来的这一行c的值就是0,与原库的值不同。

    2. 先写binlog后写redo log。如果在binlog写完之后crash,由于redo log还没写,崩溃恢复以后这个事务无效,所以这一行c的值是0。但是binlog里面已经记录了“把c从0改成1”这个日志。所以,在之后用binlog来恢复的时候就多了一个事务出来,恢复出来的这一行c的值就是1,与原库的值不同。

    可以看到,如果不使用“两阶段提交”,那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致。

    不只是误操作后需要用这个过程来恢复数据。当你需要扩容的时候,也就是需要再多搭建一些备库来增加系统的读能力的时候,现在常见的做法也是用全量备份加上应用binlog来实现的,这个“不一致”就会导致你的线上出现主从数据库不一致的情况。

    简单说,redo log和binlog都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。

    事务

    当数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题,为了解决这些问题,就有了“隔离级别”的概念。

    隔离得越严实,效率就会越低。因此我们在二者之间寻找一个平衡点。

    SQL标准的事务隔离级别包括:读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable ):

    • 读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。
    • 读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。
    • 可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
    • 串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

    Oracle数据库的默认隔离级别其实就是“读提交”,因此对于一些从Oracle迁移到MySQL的应用,为保证数据库隔离级别的一致,你一定要记得将MySQL的隔离级别设置为“读提交”。

    事务隔离的实现

    在MySQL中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。

    假设一个值从1被按顺序改成了2、3、4,在回滚日志里面就会有类似下面的记录:

    ,不同时刻启动的事务会有不同的read-view。如图中看到的,在视图A、B、C里面,这一个记录的值分别是1、2、4,同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)。对于read-view A,要得到1,就必须将当前值依次执行图中所有的回滚操作得到。

    回滚日志会当系统里没有比这个回滚日志更早的read-view的时候被删除

    为什么不要用长事务

    1. 长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。
    2. 长事务还占用锁资源,也可能拖垮整个库

启动

MySQL的事务启动方式有以下几种:

  1. 显式启动事务语句, begin 或 start transaction。配套的提交语句是commit,回滚语句是rollback。
  2. set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个select语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行commit 或 rollback 语句,或者断开连接。

有些客户端连接框架会默认连接成功后先执行一个set autocommit=0的命令。这就导致接下来的查询都在事务中,如果是长连接,就导致了意外的长事务。

因此,我会建议你总是使用set autocommit=1, 通过显式语句的方式来启动事务。

但是有的开发同学会纠结“多一次交互”的问题。对于一个需要频繁使用事务的业务,第二种方式每个事务在开始时都不需要主动执行一次 “begin”,减少了语句的交互次数。如果你也有这个顾虑,我建议你使用commit work and chain语法。

在autocommit为1的情况下,用begin显式启动的事务,如果执行commit则提交事务。如果执行 commit work and chain,则是提交事务并自动启动下一个事务,这样也省去了再次执行begin语句的开销。同时带来的好处是从程序开发的角度明确地知道每个语句是否处于事务中。

你可以在information_schema库的innodb_trx这个表中查询长事务,比如下面这个语句,用于查找持续时间超过60s的事务。

select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60

索引

数据库索引模型

  1. 哈希表
    • 适用于等值查询,比如Memcached及其他一些NoSQL引擎
    • 查询效率高,但不支持范围查询
    • 插入删除效率低,可能会出现哈希冲突
  2. 有序数组
    • 在等值查询和范围查询场景中的性能就都非常优秀
    • 查询效率高
    • 插入删除效率低,需要移动数据
    • 有序数组索引只适用于静态存储引擎
  3. B+树
    • InnoDB采用B+树作为索引模型
    • 支持等值查询和范围查询
    • 查询效率高,插入删除效率也较高

InnoDB索引组织结构

example

从图中不难看出,根据叶子节点的内容,索引类型分为主键索引和非主键索引。

主键索引的叶子节点存的是整行数据。在InnoDB里,主键索引也被称为聚簇索引(clustered index)。

非主键索引的叶子节点内容是主键的值。在InnoDB里,非主键索引也被称为二级索引(secondary index)。

  1. 主键索引对应聚集索引
    • 数据按主键物理顺序存储;主键查询只需要搜索B+树就行
  2. 辅助索引的叶子节点为主键值
    • 通过主键索引查找数据,普通索引需要先搜索引树得到ID的值,在到ID索引树搜索,称为回表操作;

也就是说,基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询

主键选择

  1. 自增主键
    • 插入顺序,不会触发分裂
    • 空间占用小
  2. 业务主键
    • 更符合实际需求
    • 也可以直接作为主键索引

B+树维护操作

  1. 插入如果导致页满,需要分裂页
  2. 删除如果导致页利用率低,需要合并页

索引重建问题

  1. 直接使用ALTER TABLE效率可能不高
  2. 应考虑使用线上DDL或备份还原方式

显然,主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小。

所以,从性能和存储空间方面考量,自增主键往往是更合理的选择。

有没有什么场景适合用业务字段直接做主键的呢?还是有的。比如,有些业务的场景需求是这样的:

  1. 只有一个索引;
  2. 该索引必须是唯一索引。

覆盖索引

  • 定义:如果一个索引包含了查询所需的所有字段,则称为覆盖索引。
  • 优点:能够减少数据库访问成本,因为可以直接在索引中获取数据,无需回表到主数据文件。
  • 应用:例如,在查询 SELECT ID FROM T WHERE k BETWEEN 3 AND 5 中,如果索引 k 已经包括 ID 字段,则此索引覆盖了查询需求。

最左前缀原则

  • 定义:在使用复合索引时,查询条件可以使用索引的最左边的一个或多个字段来优化查询。
  • 优点:使得数据库能够利用索引快速定位数据,减少扫描范围。
  • 实例:在联合索引 (name, age) 中,查询可以利用 namenameage 的组合来加速,但不能只用 age

索引下推

 无索引下推执行流程

索引下推执行流程

  • 定义:MySQL 5.6及以上版本的优化技术,允许在索引层面过滤数据,而不是在找到完整记录后才进行过滤。
  • 优点:减少了不必要的数据加载和回表操作,提高查询效率。
  • 示例:在 name, age 索引中,查询 SELECT * FROM tuser WHERE name LIKE '张%' AND age = 10 可以直接在索引层过滤掉不符合 age 条件的记录。

策略选择和权衡

  • 联合索引的选择:在创建联合索引时,应考虑查询模式以及字段在查询中的频率和顺序。正确的字段顺序可以减少冗余索引,优化存储和维护成本。
  • 索引的成本:尽管索引可以提高查询性能,但它们也会增加写操作的负担,并占用额外的存储空间。因此,在添加索引前需要权衡其对性能的潜在影响。

建议

  • 覆盖索引使用建议:对于高频查询特别是在只需要表中少数几个字段的情况下,考虑使用覆盖索引。
  • 索引审查:定期审查现有索引的效能和必要性,移除不再有效或重复的索引,优化索引配置

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

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

相关文章

【数据可视化-02】Seaborn图形实战宝典

Seaborn介绍 Seaborn是一个基于Python的数据可视化库,它建立在matplotlib的基础之上,为统计数据的可视化提供了高级接口。Seaborn通过简洁美观的默认样式和绘图类型,使数据可视化变得更加简单和直观。它特别适用于那些想要创建具有吸引力且信…

从零开始学RSA: [WUSTCTF2020]情书等5题

1 [WUSTCTF2020]情书 题目 Premise: Enumerate the alphabet by 0、1、2、..... 、25 Using the RSA system Encryption:0156 0821 1616 0041 0140 2130 1616 0793 Public Key:2537 and 13 Private Key:2537 and 937flag: wctf2020{Decryption}解题 前提:用0、…

高效、精准:皮秒激光切割机在陶瓷基板加工中的应用

皮秒激光切割机(激光划片机)在陶瓷基板切割领域具有显著的优势和潜力,主要体现在以下几个方面: 1. 高精度:皮秒激光切割机能够实现极高的切割精度,对于陶瓷基板这种需要精细加工的材料尤为重要。它能够在不…

【网络原理】IP协议详解

一.与IP协议相关的基本概念 IP协议,即网际互连协议(Internet Protocol),是TCP/IP体系中的核心网络层协议。 网络层IP协议解决的问题 数据传输的过程中,不是直接进行的传输,而是经过层层的封装和分用的过程才能到达对端. IP协议主…

13 【PS作图】人物绘画理论-脸型

三庭五眼 三庭:脸的长度比例 (1)发际线到眉毛 (2)眉毛到鼻底 (3)鼻底到下巴 三个部分大致为三等分 五眼:脸的宽度比例 以眼睛长度为单位,把脸的宽度分成五等分&#x…

day1Qt作业

#include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {this->resize(540,415);//窗口大小this->setFixedSize(540,415);//固定窗口大小this->setWindowTitle("QQ");//标题this->setWindowIcon(QIcon("E:\\hqyjap…

大数据在互联网领域的“九大”应用

当下越来越多的应用涉及到大数据,而这些大数据的属性,包括数量,速度,多样性等等都呈现出大数据不断增长的复杂性,所以大数据的分析方法在大数据领域就显得尤为重要,目前互联网大数据运用的九大领域&#xf…

网络演进技术演进:裸纤专线、SDH、MSTP+、OTN、PTN、IP-RAN

前言 文章主要介绍常见名词以及其在各自领域实现的功能价值。 01 裸纤 裸光纤(裸光纤)由运营商提供,是无中继的光纤线路,仅通过配线架连接。相比传统光纤,裸光纤提供纯粹的物理传输路径,无需额外网…

Linux字符设备驱动-详解与实操:驱动架构、设备树、Pinctrl子系统和GPIO子系统、platform、设备树下的platform

如何编写一个驱动程序: (1)确定主设备号 (2)定义自己的file_operations结构体: 包含对应的open(drv_open)/read(drv_read)等设备操作函数,需要到内核中去注册 (3)实现…

为什么需要自动化测试?自动化有哪些优势?

前言 自动化测试,最近些年可谓是大火。招聘上的要求也好,培训班的广告也罢,比比皆是,足以说明它在业内的火爆程度。 虽然说会写自动化测试并不能说明你就很牛批,但是你不会的话,那么很抱歉,你…

力扣每日一题-拆炸弹-2024.5.5

力扣题目:拆炸弹 题目链接: 1652.拆炸弹 题目描述 代码思路 根据代码实现分为k等于0和k不等于0的情况。k等于0很容易处理,而k不等于0时,需要使用滑动窗口的方式来解决。先根据小于0或大于0确定一个窗口,然后移动,获…

【Mac】 DSync for mac(文件比较同步工具) v2.7安装教程

软件介绍 DSync是一款文件比较同步工具,通过简便的三步即可完成繁琐的比较、同步操作,您甚至可以通过跳过、删除或反转您选择的文件的复制方向来微调您的同步。这是在Mac上同步文件的最简单方法。 安装教程 1.打开安装包,将「DSync」拖到右…

YUM源仓库部署和NFS共享存储服务

一.YUM源仓库部署 1.YUM 概述 (1)是基于RPM软件包构建的软件更新机制 (2)可以自动解决依赖关系 (3)所有软件包有集中的YUM软件仓库提供 2.准备YUM源 (1)软件仓库的提供方式&…

个人直播/流媒体服务解决方案实践

目录 1. 说明 1.1 拓扑结构图 2. 准备工作 2.1 软硬件清单 3. 步骤 3.1 按上面的软硬件清单准备好材料 3.2 内网检查测试 3.3 透传到公网服务器 3.5 机顶盒配置 4. 总结 5. 参考 6. 后语 1. 说明 - 在本地局域网建立流媒体服务,并发布到公网服务器供终…

【Unity 组件思想-预制体】

【Unity 组件思想-预制体】 预制体(Prefab)是Unity中一种特殊的组件 特点和用途: 重用性: 预制体允许开发者创建可重复使用的自定义游戏对象。这意味着你可以创建一个预制体,然后在场景中多次实例化它,…

轻松上手的LangChain学习说明书

一、Langchain是什么? 如今各类AI模型层出不穷,百花齐放,大佬们开发的速度永远遥遥领先于学习者的学习速度。。为了解放生产力,不让应用层开发人员受限于各语言模型的生产部署中…LangChain横空出世界。 Langchain可以说是现阶段…

快速了解Oracle 数据库 23ai

Oracle Database 23ai 于2024年5月2日正式发布。快速了解可以看官网主页和官方博客。 官网主页 23ai的3个要点,核心都是数据: 数据的人工智能 主要指数据库内置机器学习和AI向量搜索。这实际是Oracle融合数据库策略的延续,避免了复杂的数据…

SparkStructuredStreaming状态编程

spark官网关于spark有状态编程介绍比较少,本文是一篇个人理解关于spark状态编程。 官网关于状态编程代码例子: spark/examples/src/main/scala/org/apache/spark/examples/sql/streaming/StructuredComplexSessionization.scala at v3.5.0 apache/spark (github…

电商企业案例:金蝶云星空对接易仓

案例背景 某跨境电商公司,作为行业的新锐力量,业务覆盖全球数十个国家,产品线丰富多样。随着业务量的激增,原有的信息孤岛问题日益凸显,导致订单处理延迟、库存管理混乱、物流效率低下。尤其是发货单、销售退件单等跨…

代码随想录训练营31day-动态规划4

一、完全背包(参考博客) 和01背包区别在于物品可以无限次放入背包。完全背包和01背包问题唯一不同的地方就是,每种物品有无限件。 因此在需要在遍历顺序上进行区别,参考代码随想录: 二、518.零钱兑换II 题目求的是组…