深入理解索引B+树的基本原理

news2024/10/6 0:36:57

目录

1. 引言

2. 为什么要使用索引?

3. 索引的概述

4. 索引的优点是什么?

4.1 降低数据库的IO成本,提高数据查找效率

4.2 保证数据库每一行数据的唯一性

4.3 加速表与表之间的连接

4.4 减少查询中分组与排序的执行时间

 5. 索引的缺点是什么?

5.1 创建索引和维护索引非常耗费时间

5.2 索引也是占用磁盘空间的

5.3 索引会降低表的更新速度

6. B+ 树到底是什么样的?

7. 数据库底层存储数据的实质

8. 索引的实现原理

9. 为什么B+树的高度不建议超过四层?

10. 什么是聚簇索引?

10.1 聚簇索引的特点

10.2 聚簇索引的优点?

10.3 聚簇索引的缺点?

10.4 聚簇索引的补充说明

11. 什么是非聚簇索引?

12. 什么是回表?

13. 为什么非聚簇索引的叶子节点不存储一份完整的数据方便查找呢?

14. 聚簇索引与非聚簇索引的区别?

15. 什么是联合索引?


1. 引言

我们知道,只要谈起数据库,索引重中之重,不管你是面试开发程序员,架构师,甚至是校园招聘,你会发现几乎都问到了索引。那么它到底是个什么东西?竟能如此重要。它到底有什么好处呢?为什么面试的时候总喜欢问索引呢?它的底层实现是什么样的呢?今天我们就一同来揭晓这些问题的答案。

提前声明,想要更加透彻深入的学会索引,建议你对数据结构有很好的了解,特别是树和链表,如果你对树这种结构很清晰,那么学会索引非常轻松,如果不会,也没关系,并没有很大影响。

2. 为什么要使用索引?

想要理解索引,我们首先要知道为什么要使用索引。

我来说一个场景,假设现在我的一张用户表中有十万条用户数据,用户 id 唯一,我想要查询id 位80000的用户信息,那么数据库是靠什么快速的在十万条数据中找到这条id为80000的用户数据的呢?各位有没有想过这个问题?

其实底层就是索引在帮忙,做一个简单的比喻,如果我们把刚才的用户表中的数据存放到一本字典中,那么索引就是这个字典的目录,当我们想要查找某一个数据的时候,数据库底层不会傻乎乎的去一页一页从字典中翻找我们想要的数据,而是直接去翻这根本字典的目录,通过目录精准定位我们想要查询的数据在哪一页,然后直接定位到那一页,将我们要查找的数据取出。

那么各位再想一下,如果字典没有目录。会是什么样的结果呢?我们要查找用户张三的信息,然后数据库受到了指令,从第一页开始翻看查阅,没有翻到第二页,有没有翻到第三页......各位想过没有,这会多麻烦,所以,通过字典目录提高查找效率是必须要做的,通过索引查找数据也是迫在眉睫的,但同样,我们既然制造了目录,如果我们对字典中的数据做了更改,目录是不是也要改啊,这就为我们后续索引的缺点做了铺垫。

总结来说就一句话,之所以要使用索引,是因为索引可以提高我们查找数据的效率。

3. 索引的概述

MySQL官方给索引的定义是:索引(Index)是帮助MySQL高效获取数据的数据结构。

简洁点来说,索引的本质是数据结构。

此外,索引是在存储引擎中实现的,当我们的存储引擎不同时,索引底层的数据结构也不相同。

同时,存储引擎中还定义了一个表中最多不能超过16个索引,但其实我们也用不到这么多,所以完全可以放心;也定义了索引的长度不能超过256个字节,其实也很大了,我们通常不会把索引定义那么大,也可以放心。

4. 索引的优点是什么?

4.1 降低数据库的IO成本,提高数据查找效率

各位细想,我们的数据都是存储在磁盘上的,只有我们在需要的时候才会从磁盘IO读取到内存中。那么用户表的那本字典,如果没有索引,我会就会先从磁盘IO加载第一页的数据到内存,然后遍历数据,发现没有找到,再经过IO磁盘,加载第二页的数据到内存,再遍历查找...... 各位知道,内存中数据的处理速度是很快的,但是从磁盘加载到内存这个速度就很慢了,假设我们遍历一页数据需要1ms,那么IO一次可能就需要50ms,这还只是加载了第一页的数据,那如果有很多很多页数据,查找速率绝对非常慢。但是如果我们使用了索引,我们只需要IO一次将索引加载到内存中,遍历索引,精准找到数据所在的页数,然后第二次IO直接读取是数据所在的那一页数据,这样的话,只需要经过两次磁盘IO就可以得到我们需要的数据了。

4.2 保证数据库每一行数据的唯一性

我们知道,表中通常都是有主见的,而且都会设置为非空且唯一,我们的索引也是一样,索引也是具有唯一性的,通过创建唯一索引,可以保证数据库表中每一行数据的唯一性。

4.3 加速表与表之间的连接

对于有父子关系的子表与父表在进行联合查询时,索引可以加速表与表之间的连接,从而提高表的查询效率。

4.4 减少查询中分组与排序的执行时间

各位想一下,字典中的目录我们都是按照一定的规律去进行排列的,索引也是一样的道理,从小到大把数据进行排列,既然是已经排好序的数据了,当我们在查询语句中对数据进行ORDER BY 排序时候,其实已经是有序的了,那么就省去了我们再次排序的时间,而且以后查询排序都不需要浪费时间,是一个一劳永逸的做法。

 5. 索引的缺点是什么?

5.1 创建索引和维护索引非常耗费时间

这一点我想不难理解,各位想,当我们对一本书中的内容做了更改之后,你是不是也要去更改目录啊,特别是你的书内容如果不较多,如果你删除了几页内容,其他的内容都要跟着做调整;如果你一直往书中继续写内容,目录也要跟着增多吧,所以说,索引的创建与维护也是非常浪费时间的。

5.2 索引也是占用磁盘空间的

则会就好比是一本书,你书中的内容需要用纸张去些内容,那么目录也要写在纸上啊;而且索引本身就是数据结构,是需要占用磁盘的空间的,并且随着你数据量的增大,你索引所占的磁盘空间大小很有可能会超过数据本身所占的磁盘文件大小。

5.3 索引会降低表的更新速度

其实这一点与维护索引是有一些内在关联的,如果我们对表中的数据做了动态修改,那么索引也是会不断地去动态修改维护的,这就大大的降低了表的更新速度。

6. B+ 树到底是什么样的?

我们知道,数据结构中有一种数据结构叫做树,我们最常见的就是二叉树,还是平衡二叉树,还有二叉树的升级版红黑树。

既然有二叉树,就有三叉树,N叉树。

其实,B+树底层就是一个N叉树,这里我以三叉树为例,模型如下图所示

我们的对顶层就是根节点,中间层是子节点,最下层是叶子节点。

在数据库底层 InnoDB 存储引擎中,存储数据和索引就是采用B+树的形式存储的。

7. 数据库底层存储数据的实质

如上图所示,是我们数据库中常见的一张表,这里有很多的数据,但是在底层,你们知道吗,表的每一行数据都是单独存储的,在磁盘上的存储位置是不连续的。因为如果我们表中的数据有很多,达到了上万条数据,那么在磁盘中不一定有那么大的一个连续空间,因此在数据库底层,它的每一行数据都是单独存储的,而且还要满足一个逻辑上的连续,我们 employee_id = 100 的员工下一条记录是 employee_id = 101 的员工这一点是不能变的,不能说我查一次,它们的顺序就变一次,一定要它们保持一定的逻辑连续性。

说到这里各位应该就明白了吧,没错!就是链表,其实表中的每一行数据在磁盘底层是采用单向链表的形式来存储的,这样不仅解决了存储空间大小不够问题,还解决了让它们在逻辑上满足连续性的问题。

就拿上面这张表举例,在数据库的底层,employee_id = 100 的员工就是链表的头节点,它内部还会存储 employee_id = 101 的员工的地址值,从而找到该员工的全部相关信息,而employee_id = 101 的员工内部也会存储 employee_id = 102 的员工的地址值,通过该地址值找到 employee_id = 102 的员工全部信息由此形成一个单向链表。

8. 索引的实现原理

如上图,根据上面B+树的结构,我们就能大致推演出索引的底层原理了,这里我化繁为简,简单说明。

我们先看最下层,最下层也是叶子节点页,这些叶子节点页之间是使用双向链表进行连接的,而内部的数据则是我刚刚说的通过单向链表连接的,图中已经标识出,而且每一页中都有一个数组,存放主键的值,方便我们后续使用二分法快速确定要查找的数据。在B+树索引中,所有的真实数据都是存放在叶子节点叶中的,如图,在叶子节点中页10中,下方的 1,4,u;3,9,d;4,4,a 就是一条条真实的数据,上方的0就是指这些是数据,假设1,3,4这些首字段为一条条数据的主键。

我们继续推演,如果没有中间层页30与页32,只有最下方一层,当我们想要找想要查找主键为100的用户信息时,就需要从页10开始从头遍历这个双向链表,在遍历到页9的时候,找到了主键为100的用户,我们直接获取到该用户的信息,一共遍历了3页,需要进行三次磁盘IO。

如果我们加上中间层,为每一个叶子节点页再创建一个目录,即页30与页32,页30下方存储了1,10;5,28;12,9;209,20四条数据。这里的1,10中的1指代的就是叶子节点页10中最小的一条数据1,10则是指代页10,实际存储的是页10的内存地址;5,28则是叶子节点页28中的最小主键值5与该页所在的地址值,这些数据上方都是1,表示他们仍然是目录页而不是真实的数据...... 我们使用了这个中间目录页之后,我们再去获取主键为100的用户数据时,就会先去遍历中间页,在中间页中确定主键值为100的用户数据存放在页9中,就可以直接将页9中的数据全部读取到内存,然后再去寻找该用户的数据,可以发现,此时加上了中间页之后,只需要两次IO,节约了时间,提高了查找效率。

我们继续类比推理,如果以后我的数据越来越多,中间也最多只能存放四个叶子节点页的数据,再多就存不下了,这个时候,我们就需要继续创建新的中间页,而如果中间页一直增多,就会面临和刚才叶子节点页一样的问题。

这个时候,我们就可以套娃式的去再创建一个中间页的顶层也,让这个顶层页使用类似的手段存放中间页的重要数据。举例说明,我们想要查找主键为300的用户数据,第一次磁盘IO,我们把页33的全部数据加载到内存中,经过二分查找判断发现与主键为300的用户数据应存放在子页30中,在然后进行第二次IO,将子夜30的全部数据加载到内存中,再经过二分查找判断,确定主键为300的用户数据存应放在叶子节点页20中,在进行第三次磁盘IO,将叶子节点页20中的数据全部加载到内存中,再经过二分查找,快速定位到主键为300的用户所在的内存地址,获取到信息,此时只需要经历三次磁盘IO,而且非常稳定,当我们想要查询某条数据是,都是进行三次磁盘IO就可以获取到结果,找得到或找不到都要返回,极大的保证了我们查找数据时的稳定性。

9. 为什么B+树的高度不建议超过四层?

在刚才我举得例子中,各位应该看得出来,我所举例的B+树是三层,绝大多数情况下都是三层,最多四层。而在面试的时候,有些面试官会问你为什么B+树的不建议超过四层,请给出具体的原因。

原因如下:

不知道各位发现了没有,当我们的B+树只有两层时,我们最多就可以经过两次磁盘IO就可以查找到数据,当B+树是三层时,我们进行三次磁盘IO就可以获取到数据。这也从侧面印证了一点,我们与磁盘交互的次数,是受到B+树高度的影响的,各位都知道,内存中处理数据速度是非常快的,二分查找数据可能就1ms~3ms左右的时间,而与磁盘IO就不一样了,磁盘IO一次可能就需要花费100ms,每交互一次100ms,这个效率是非常低的,因此我们应当尽量减少与磁盘的IO次数,这就要求我们B+树的高度不能过高,最好三层,不能超过四层。

那肯定会有人问,问什么非要是三层或四层,我选五层不行吗?

其实从原则上来讲也是可以的,但是我们还要考虑数据的存储量,这里给各位说一下,数据库的底层一个真实的数据页大小是16KB,也就是 16000 个字节,假设我们的每条数据占用160个字节,160个字节已经不小了,完全够用,那么我们每个叶子节点页就可以存储 16000/160 = 100 条数据。而我们的非叶子节点页,因为并没有存储真实的用户数据,所以可以存储更多的内容,假设我们的目录页可以存储 1000 条叶子节点页数据,当我们的B+树正好满两层的时候,存储的数据量是 100 * 1000 = 100,000 十万条数据;当我们 B+ 树满两层时,存储的数据量是 100 * 1000 * 1000 = 100,000,000 一亿条数据;让我们的B+树满5层时,存储的数据量是 100 * 1000 * 1000 * 1000 = 100,000,000,000 一千亿条数据,可以看到,当B+树5层的时候,数据量已经非常恐怖了,而且我们也不可能在一张表中存储这么多数据。

而在实际开发业务的时候,我们会采用微服务的架构,并对数据库进行分库分表,进行读写分离,不会让大量数据在同一张表中存储,既不安全,效率又低。因此,我们通常会把B+树控制在三层左右,此时一张表就足以存储一亿条数据,而且只需要三次磁盘IO就可以查找到想要的数据,综合考虑是最优的选择。如果像阿里京东腾讯这些用户量多余1亿的企业,也有可能会采用四层B+树,但其实还是是很少这么做的。这就是为什么要把B+树的高低控制在四层以下,总的来说就一句话,三层或四层B+树,既满足了数据量的存储需要,又达到了最佳查找效率。

10. 什么是聚簇索引?

聚簇索引,又名主键索引,它是基于表的主键而生成的索引,而且它不是一种索引的类型,而是一种数据的存储方式(表中所有的用户数据都会存放在叶子节点中)如下图所示就是一个经典的聚簇索引。在 InnoDB 引擎中,聚簇索引是不需要我们手动创建的,在我们创建好表结构的时候,数据库的底层已经为我们生成聚簇索引,并随着我们数据的添加,索引会一直不断的变化和维护。

10.1 聚簇索引的特点

聚簇索引还有一些特点,只有满足以下四点的索引才能称为聚簇索引:

1. 每个页内的记录是按照的主键的大小顺序形成的一个单向链表,例如页10中的(1,4,u)与(3,9,d)便是通过单向链表连接的;

2. 各个存放的数据页之间采用的是双向链表进行连接,如图中的页10与页28之间就是双向链表;

3. 存放目录项记录的页(即刚才我所提的中间层)它们之间也是采用双向链表的形式进行连接,如图中的页30与页32就是双向链表;

4. B+ 树中存放的是完整的表数据,如图中页10的(1,4,u),(3,9,d)等,这里我列的简单,只有三个字段,实际聚簇索引存储的数据会以你定义的表中的字段为主;

10.2 聚簇索引的优点?

(1)因为聚簇索引中将索引与所有的表数据都存储在了B+树种,所以聚簇索引比非聚簇索引查询效率要高

(2)因为聚簇索引是基于主键大小排列的索引,所以对于主键的范围查找与排序查找速度非常快

(3)因为聚簇索是引按照一定的顺序进行排列,再查询显示一定范围的数据的时候,由于数据是紧密相连的,数据库就不需要从不同的区块中去提取数据,节省了大量的IO操作

10.3 聚簇索引的缺点?

(1)插入的速度严重依赖于插入的顺序。因为聚簇索引是按照逐渐的顺序去建立的,如果我们不按照顺序去插入,而是突然插入一个主键值大的数据,又突然插入一个主键值小的数据,这就会导致索引会不断地去动态变化,还可能出现页分裂,严重影响性能,因此对于 InnoDB 引擎来说,建议在插入数据的时候按照顺序插入或者使用主键自增策略。

(2)更新主键的代价极高。因为聚簇索引就是基于几件生成的,如果我们对主键做出更改,那么整个索引结构可能都要进行更改,而进行更改是非常耗费性能的,因此对于 InnoDB 引擎来说,我们一般最好把主键定义为不可更改。

10.4 聚簇索引的补充说明

(1)MySQL 数据库目前只有 InnoDB 引擎支持聚簇索引,MyISAM 引擎不支持聚簇索引;

(2)由于数据物理存储排序方式只有一种,所以每个 MySQL 表只能有一个聚簇索引,一般情况下都是该表的主键;

(3)如果我们没有给表定义主键,那么 InnoDB 会选择一个非空且唯一的字段替代,如果也没有这样的字段,那么 InnoDB 会隐世式定义一个主键作为聚簇索引;

(4)为了充分利用聚簇索引的特性, InnoDB 引擎下在定义表的主键的时候,不建议使用无序的id,例如UUID,MD5,HASH,字符串等作为主键,否则无法保证数据的顺序增长。

11. 什么是非聚簇索引?

非聚簇索引,也可以叫二级索引,或叫辅助索引。

刚才我们说到了,聚簇索引是 InnoDB 引擎基于主键自动生成的,可以提高有关主键的查找速度和查找范围,也就是说只有搜索条件中包含主键字段时才有效果。那么当我们不使用主键字段来查找数据而是基于普通字段查找数据同时又想提高查找效率的时候,我们就可以通过普通字段定义非聚簇索引。如下图所示就是一个非聚簇索引所构成的 B+ 树。

这里需要注意一点,非聚簇索引构成的 B+ 树与聚簇索引构成的 B+ 树稍有不同。

这里目录页44与子目录页42,43的原理与聚簇索引中类似,但叶子节点中就不一样了,刚才我说到了,聚簇索引中,存放着完整的表数据,而在非聚簇索引中,叶子节点中只存放着索引对应的那个普通字段与主键值。如图中,蓝色对应的就是普通字段,黄色对应的就是主键值,我们可以看一下,在前面那张图中,页9中存放这一条数据(20,2,e),正好对应着我们这里的非聚簇索引,这里页34下面蓝色方块中值为2的数据对应的主键值也为20,这样说各位同学应该更好理解一些,各位可以将上图与前面聚簇索引中的字段值做对比就可以看出来,我就不一一举例说明了。

12. 什么是回表?

刚才我说到了,在非聚簇索引中,叶子节点只存放了该索引字段的相关信息和主键信息,那么只有这两项信息肯定是不够的,如果我们的目的是通过非聚簇索引查询某条用户的全部信息,它就会进行回表操作,什么是回表呢?

其实很简单,当我们使用非聚簇索引的字段作为查询条件去查询表中的相关信息时,数据库会先根据非聚簇索引形成的 B+ 树,一步步查找到与查询条件相关的信息,再根据它们各自对应的主键去聚簇索引中查询完整的用户信息,这个过程中,需要先查询非聚簇索引的 B+ 树,再去查询聚簇索引的 B+ 树,查询之后又回去再查了一次表,这个过程就叫做回表。

举个栗子,现在有一张表 user ,主键 uid ,手机号码 phone,用户名 username,密码 password四个字段,我们给手机号码字段创建了非聚簇索引,那么它的底层就会只存储手机号码信息和所对应的主键uid 信息,当我们通过 手机号去查询用户完整信息时,语句应该是 SELECT * FROM user WHERE phone = "待查询用户手机号";在这个查询语句中,它会先去非聚簇索引形成的 B+ 树通过 phone 查找到对应的主键uid,查找到主键uid的信息之后,它会再去聚簇索引的 B+ 树中通过 uid 查询出完整的用户信息并返回,这就是它在底层的执行逻辑,先查非聚簇索引,再回表查聚簇索引。

13. 为什么非聚簇索引的叶子节点不存储一份完整的数据方便查找呢?

这个问题其实也算是一个面试题。我刚才说了什么是回表,但是不知道各位发现一个问题没有,回表还需要再查寻一次 B+ 树,这样不是很麻烦吗?我们直接将用户的全部信息在非聚簇索引的 B+ 树中叶存储一份多省事啊,怎么不这样做呢?

如果你也有这样的问题,说明你认真思考了。大家想一想,在聚簇索引中,我们已经存储了一份完整的表数据,还有 B+ 树的结构,这些都是非常占用磁盘满空间的,而非聚簇索引又不止可以创建一个,我们可以创建多个,刚才我举的例子中只有四个字段,在实际的业务场景中,二十个字段也是很有可能的,如果我们为了方便查找又创建了三个非聚簇索引,并且图方便在非聚簇索引中也存储完整的用户数据,各位同学想一想,这样是不是非常冗余,我们的用户数据明明存储一份就够了,但是你创建一个非聚簇索引,数据就多存储一份,再创建一个,再存储一份,我们创建三个非聚簇索引,那么加上聚簇索引我们底层的数据足足存储了四份,非常非常冗余,这是绝对不允许的。另外,如果我们把全部的数据都存在非聚簇索引中,那么当我们要对用户数据作出修改时,有多少个索引,我们就要修改多少次,各位想是不是,我们对用户张三做修改,所有的索引中关于张三的信息都要做修改,非常不划算不值得。所以不在非聚簇索引上也存储一份完整的用户数据,一方面是为了防止数据大量冗余,造成磁盘资源的浪费;另一方面是防止多余的操作。

14. 聚簇索引与非聚簇索引的区别?

(1)聚簇索引叶子节点存储的是完整的用户数据,而非聚簇索引中存储的只有主键与索引字段数据,非聚簇索引不会影响表的物理存储结构;

(2)一个表只能有一个聚簇索引,但是可以有多个非聚簇索引;

(3)使用聚簇索引时,查询效率很高,但如果是对数据进行增删改操作,效率会比非聚簇索引低;

15. 什么是联合索引?

说的准确一些,联合索引其实属于是非聚簇索引中的一种,它与我们说的联合主键是有一些类似的,刚才我们说的非聚簇索引是使用一个字段构成 B+ 树,而有些时候我们会把数据库中的两个字段都作为索引,这种情况下形成的索引就叫联合索引。

举个例子,假设一张学生表 student ,有主键字段C1,非主键字段C2,C3,C4,C5。现在我们为C2与C3创建联合索引,那么形成的 B+ 树中就会存放 C2,C3,C1字段,并按照从上到下的顺序排列,会先比较联合字段C2的大小,先按C2大小排序,当C2大小相同时,再根据C3大小排序,在下方存贮主键C1的值,从而形成一个联合索引 B+ 树。

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

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

相关文章

abp(net core)+easyui+efcore实现仓储管理系统——组织管理升级之下

在“组织管理”列表页面中使用鼠标勾选想要进行修改的组织信息,然后点击“修改”按钮。如下图。 14.此时会弹出“修改组织信息”界面,但界面上没有显示我们勾选的那一条组织信息的任何数据。如下图。 15.由于我们的功能主要都在javascript中写的&#x…

Python语言入门简介

一、Python的历史 关键点: Python是一种用途广泛、解释性、面向对象的程序设计语言。 Python是新西兰的Guido van Rossum在1990 年创建的,它以英国流行喜剧“Monty Python的飞行马戏团”命名。van Rossum将Python开发作为一个嗜好,Python 因其简单、简洁…

聊聊在集群环境中本地缓存如何进行同步

前言 之前有发过一篇文章聊聊如何利用redis实现多级缓存同步。有个读者就给我留言说,因为他项目的redis版本不是6.0版本,因此他使用我文章介绍通过MQ来实现本地缓存同步,他的同步流程大概如下图 他原来的业务流程是每天凌晨开启定时器去爬取…

硬盘文件恢复怎么做?文件恢复,问题已解决!

“请问一下可以帮我恢复硬盘里的文件吗?我之前删除了一些重要的文件和数据,但是最近我突然想起来那些文件是很有用的,有没有什么好的方法可以帮我恢复硬盘中的文件呢?” 硬盘作为电脑的存储设备,电脑用户通常会将各种重…

du -mh命令

du 命令查看每个文件夹大小(du 命令用法详解),du 命令的英文全拼是 disk usage,意思是占用的磁盘空间,该命令可以显示目录或文件的大小。 在执行“ du ”命令时,使用“ -h ”参数会以“人类可读格式”显示…

Android高手进阶教程(三)之----Android 中自定义View的应用.

大家好我们今天的教程是在Android 教程中自定义View 的学习&#xff0c;对于初学着来说&#xff0c;他们习惯了Android 传统的页面布局方式&#xff0c;如下代码: <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"htt…

C#Winform中读取Excel表格数据并显示到DataGridView控件实例

本文讲解Winform中读取Excel表格数据并显示到DataGridView控件实例 首先创建winform项目,添加控件DataGridView和button 修改CS文件 using System; using System.Data; using System.Data.OleDb; using System.Diagnostics; using System.Windows.Forms;namespace DataGridv…

OpenAI推出新产品GPTBot:可爬取网络数据,为GPT-5做准备

昨天发的《量子论公众号是如何半年做到10000粉的&#xff1f;》&#xff0c;好像没人感兴趣&#xff0c;那以后不发此类话题了。 今天的内容也是翻看Hacker News上的帖子里发现的。 近期&#xff0c;OpenAI官网介绍了一款新产品GPTBot。可是&#xff0c;这款产品对我们没什么用…

Clickhouse基于文件复制写入

背景 目前clickhouse社区对于数据的写入主要基于文件本地表、分布式表方式为主&#xff0c;但缺乏大批量快速写入场景下的数据写入方式&#xff0c;本文提供了一种基于clickhouse local 客户端工具分布式处理hdfs数据表文件&#xff0c;并将clickhouse以文件复制的方式完成写入…

直播源码异步处理技术:应对处理大量用户请求的挑战

在网络技术的快速发展背景下&#xff0c;直播源码平台已经成为了人们社交娱乐的重要工具&#xff0c;直播源码平台的用户会在平台内进行观看直播、短视频&#xff0c;与其他用户进行交流、交谈。由于直播源码平台用户数量的逐日增加&#xff0c;使得直播源码平台每天要应对、处…

vim插件

点击vim官网左边列表的Scripts链接&#xff0c;如下&#xff1a; 然后再点击Browse all链接&#xff0c;如下&#xff1a; 然后在出现的插件列表界面中还可以选择排序方式&#xff0c;比如按下载量降序排序&#xff0c;如下&#xff1a; 好用的插件&#xff1a;EasyMotion&…

算法|Day40 动态规划9

LeetCode 198- 打家劫舍 题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 题目描述&#xff1a;你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房…

Vue学习之绑定样式

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>绑定样式</title><style>.basic{width:400px;height:100px;border:1px solid black;}.happy{border:4px solid red;background-color: rgba(255, 255, 0, 0.644…

python优雅地爬虫!

背景 我需要获得新闻&#xff0c;然后tts&#xff0c;在每天上班的路上可以听一下。具体的方案后期我也会做一次分享。先看我喜欢的万能的老路&#xff1a;获得html内容-> python的工具库解析&#xff0c;获得元素中的内容&#xff0c;完成。 好家伙&#xff0c;我知道我爬…

ROS相关技术(经验版)

重要说明&#xff1a;本文从网上资料整理而来&#xff0c;仅记录博主学习相关知识点的过程&#xff0c;侵删。 一、参考资料 ROS相关技术介绍&#xff0c;可参考之前的文章&#xff1a;ROS相关技术&#xff08;概念版&#xff09; Autolabor主站 ROS官网 ROS ROS教程 ROS编程…

小红书如何打造爆款引流吸粉?11个秘诀助你秒变达人!

在这个充满信息和内容的时代&#xff0c;小红书以其独特的社交平台特性和个性化内容吸引了众多用户。今天&#xff0c;我们就来揭秘小红书关注战略&#xff0c;了解如何在这个平台上打造独特的内容体验&#xff0c;与用户建立更亲近的连接。#小红书# 1、定位清晰&#xff0c;找…

数字化车间mes生产执行管理系统

数字化车间mes是一款基于B/S结构的生产执行管理系统&#xff0c;主要目的是为中小企业提供了高效率、低成本、通用性强的一个MES系统解决方案&#xff0c;能够实时监控当前完成进度。 功能简介&#xff1a; 生产管理 大屏展示&#xff1a;可以从大屏展示页面看到任工序…

C++ 二叉树(建立、销毁、前中后序遍历和层次遍历,寻找双亲结点等)

&#xff08;1&#xff09;结构体和类定义 struct BTreeNode {T data;BTreeNode* left, * right;BTreeNode() :data(0), left(nullptr), right(nullptr) {}BTreeNode(T val, BTreeNode<T>* leftChild nullptr, BTreeNode<T>* rightChild nullptr):data(val), le…

两个pdf合并成一个pdf怎么合并?这几个方法值得推荐

两个pdf合并成一个pdf怎么合并&#xff1f;pdf文件的合并是一个很常见的需求&#xff0c;特别是在处理工作文件或学习资料时。为了更好的帮助你了解如何将两个pdf文件合并成一个&#xff0c;下面就给大家详细介绍几种合并方法。 方法一&#xff1a;使用迅捷PDF转换器 这是一款…

【虫洞攻击检测】使用多层神经网络的移动自组织网络中的虫洞攻击检测研究(Matlab代码实现)

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