【MySQL】索引内部数据结构

目录

索引是什么?

几种数据结构介绍:

二叉查找树(Binary Search Tree,BST):

红黑树:

平衡二叉查找树:

多路平衡查找树B-Tree(balanced tree):

B+Tree:

HASH

mysql索引数据结构:

按照索引方法划分:

B+Tree

hash

MySQL B+Tree落地形式

innodb-聚簇索引

MyISAM-非聚簇索引

按照逻辑角度划分:

普通索引:

唯一索引:

主键索引

联合索引(又叫复合索引):

全文索引:

索引覆盖:

IO原理:

局部性原理:

B+Tree 一个节点到底存多少元素合适?

mysql中B+Tree的一个节点大小为多大呢?

为啥一个节点为1页(16K)就够了?

When?

哪些情况需要创建索引?

哪些情况不需要创建索引?


索引是什么?

除数据本身以外,数据库还维护着一个满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就可以在这些数据结构的基础上实现高级查找算法,这种数据结构就是索引。

快速检索出数据的数据结构。

一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以文件形式存储在硬盘上。

几种数据结构介绍:

可以通过如下网址进行数据结构查看:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

现在从二叉查找树、平衡二叉树、多路平衡查找树B-Tree、B+Tree依次分析一下:

二叉查找树(Binary Search Tree,BST):

  • 是一棵相对平衡的有序二叉树
  • 对其进行插入、查找、删除等操作,平均复杂度均为O(logn)
  • 左子节点比父节点的值小,右节点的值比父节点的值大

如果组织结构不好,就会组成线性的结构,查找也不是很好

红黑树:

相对平衡

平衡二叉查找树:

  • 它的左右两个子树的高度差的绝对值不超过1

缺点:

  • 搜索时IO次数过多
  • 节点数据内容较少,这样就会导致高度变高,查找的IO次数过多                                                                                           

例如:如果查找关键字为8的话,需要进行3次IO操作。

  1. 根据根节点找到磁盘块10,读入内存,CPU进行比较  8 < 10【磁盘进行一次I/O操作】
  2. 磁盘,5,内存,CPU  8 > 5
  3. 磁盘,8,内存,CPU  8 > 8

 

多路平衡查找树B-Tree(balanced tree):

  • 是绝对平衡的。
  • 所有叶子节点都在同一层,且不包含其它关键字信息 
  •  每个节点中不仅包含数据的key值,还有data值。 叶子节点和非叶子节点都会存储数据。                                                          而每一个页的存储空间是有限的,如果data数据较大时将会导致每个节点(即一个页)能存储的key的数量很小,当存储的数据量很大时同样会导致B-Tree的深度较大,增大查询时的磁盘I/O次数,进而影响查询效率

 

路=关键字个数 + 1

经常改变的数据尽量不要建索引,会经常改变索引的结构(通过左旋)

 

B+Tree:

  • 非叶子节点并不保存数据相关信息,只保存关键字和子节点的引用
  • 所有叶子节点之间都有一个链指针
  • 数据记录都存放在叶子节点中(聚集索引的B+Tree中的叶子节点存放的是整张表的行记录数据)

优点:

  • 提高数据检索效率,降低数据库的IO成本
  • 通过索引列对数据进行排序,降低数据排序成本,降低了CPU的消耗缺点:
  • 实际上索引也是一张表,该表保存了主键和索引字段,并指向实体表的记录,所以索引列也是要占用空间的;
  • 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如果对表INSERT,UPDATE和DELETE。因为更新表时,MySQL不仅要不存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息
  • 索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立优秀的索引,或优化查询语句

路  =  关键字个数

 

HASH

 在memory表里,默认是hash索引, hash的理论查询时间复杂度为O(1)。

既然hash的查找如此高效,为什么不都用hash索引?

原因:

  • hash函数计算后的结果,是随机的,如果是在磁盘上放置数据。例如主键为id为例, 那么随着id的增长, id对应的行,在磁盘上随机放置。
  • 不能对范围查询进行优化.
  •  无法利用前缀索引。例如在btree中, field列的值“hellopworld”,并加索引

        查询 xx=helloword,自然可以利用索引, xx=hello,也可以利用索引(左前缀索引)

      因为hash(‘helloword’),和hash(‘hello’),两者的关系仍为随机。

  • 排序也无法优化。
  • 必须回行。就是说通过索引拿到数据位置,必须回到表中取数据。

哈希表(散列表):把Key通过一个固定的算法函数既所谓的哈希函数转换成一个整型数字,然后将该数字对数组长度进行取余,取余结果就当作数组的下标,将value存储在以该数字为下标的数组空间里。

哈希算法(散列),就是把任意长度值(Key)通过散列算法变换成固定长度的Key地址,通过这个地址进行访问的数据结构。

 

mysql索引数据结构:

按照索引方法划分:

B+Tree

hash

mysql中索引用的是B+Tree(多路平衡查找树),hash

MySQL B+Tree落地形式

插拔式,mysql中B+Tree索引体现形式分为:MyISAM、innodb

show VARIABLES LIKE 'datadir';  // 查询数据都保存在了哪里

innodb-聚簇索引

聚簇索引:主索引文件和数据文件为同一文件。

聚簇索引主要应用在innodb存储引擎中。

Innodb中主键索引的叶子节点的数据区域存储的是数据记录,辅助索引存储的是主键值。

  • 1: 主键索引 既存储索引值,又在叶子中存储行的数据
  • 2: 如果没有主键, 则会Unique key做主键
  • 3: 如果没有unique,则系统生成一个内部的rowid做主键.
  • 4: 像innodb中,主键的索引结构中,既存储了主键值,又存储了行数据,这种结构称为”聚簇索引”

优势:

  根据主键查询,不用回行(数据就在主键节点下)

  如果不是主键索引,会进行二次查找。例如上面的name为索引,如果查找name为James的那一行数据,会先查找索引为James的,指向了主键索引为1的,然后根据主键索引1找到具体那一行数据。

劣势:

  如果碰到不规则数据插入时,造成频繁的页分裂.

  节点分裂:对于innodb,节点下存储了“行数据”,分类的时候,还要移动行数据

  对于innodb的主键,尽量用整型,而且是递增的整型。如果是无规律的数据,将会产生很多的分裂。

 

MyISAM-非聚簇索引

非聚簇索引:非聚簇索引就是指B+Tree的叶子节点上的data,并不是数据本身,而是数据存放的地址。

主要用在MyISAM存储引擎中。

非聚簇索引比聚簇索引多了一次读取数据的IO操作,所以查找性能上会差。

myisam中, 主索引和次索引,都指向物理行(磁盘位置),会回行。主索引和辅助索引没啥区别,只是主索引中的key一定得是唯一的。

节点分裂:myisam,节点存储的对物理行地址,内容较小,又缓存再内存里,分类速度很快

 

按照逻辑角度划分:

普通索引:

最基本的索引,它没有任何限制。

唯一索引:

与普通索引类似,不同的就是索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。

主键索引

它是一种特殊的唯一索引,用于唯一标识数据表中的某一条记录,不允许有空值,一般用     primary key 来约束。

联合索引(又叫复合索引):

多个字段上建立的索引,能够加速复合查询条件的检索。

全文索引:

老版本MySQL 自带的全文索引只能用于数据库引擎为 MyISAM 的数据表,新版本 MySQL 5.6 的 InnoDB 支持全文索引。默认 MySQL 不支持中文全文检索,可以通过扩展 MySQL,添加中文全文检索或为中文内容表提供一个对应的英文索引表的方式来支持中文

索引覆盖:

定义:如果查询的列恰好是索引的一部分,查询只需要在索引文件上进行,不需要回行到磁盘再找数据。

优点:

  1. 可以优化缓存,减少磁盘IO操作
  2. 可以减少随机IO,使随机IO操作变为顺序IO操作
  3. 可以避免对Innodb主键索引的二次查询
  4. 可以避免MyISAM表进行系统调用


无法使用覆盖索引的情况

  1. 存储引擎不支持覆盖索引
  2. 查询中使用了太多的列
  3. 使用了双%号的like查询

IO原理:

局部性原理:

当一个数据被用到时,其附近的数据也通常会马上被使用。所以操作系统为了提高效率,读取数据时往往不是严格按需读取,而是每次都会预读,即使只需要一个字节,操作系统也会从这个位置开始,顺序向后读取一定长度的数据存放内存。这里的一定长度叫“页”,也就是操作系统操作磁盘时基本单位。一般操作系统中一页的大小是4Kb.

B+Tree 一个节点到底存多少元素合适?

B+Tree中一个节点为一页或页的倍数最为合适。因为如果一个节点的大小小于1页,那么读取这个节点的时候也会读出1页,造成资源浪费。

mysql中B+Tree的一个节点大小为多大呢?

默认大小为16K(操作系统中一页大小为4K,mysql中1页=操作系统中的4页)

可以使用:SHOW GLOBAL STATUS LIKE 'INNODB_page_size' 查看

为啥一个节点为1页(16K)就够了?

B+Tree的非叶子节点不存储数据,只有叶子节点才会存储数据。

一个节点=16K

一行数据=1K(假如)

一个叶子节点 能存放 16条数据

非叶子节点 = 索引值(bigint 8B) + 指针(6B) = 14B, 16K/14B = 1170个(索引+指针)

B+Tree高度为2的话: 1170 * 16 = 18724 条数据

B+Tree高度为3的话:1170 * 1170*16 = 21907748 条数据

 

When?

哪些情况需要创建索引?

  • 主键自动建立唯一索引
  • 频繁作为查询的条件的字段应该创建索引
  • 查询中与其他表关联的字段,外键关系建立索引
  • 单间/组合索引的选择问题(在高并发下倾向创建组合索引)
  • 查询中排序的字段,排序字段若通过索引去访问将大大提高排序的速度
  • 查询中统计或者分组字段

哪些情况不需要创建索引?

  • 表记录太少
  • 经常增删改的表
  • 数据重复且分布平均的表字段,因此应该只为经常查询和经常排序的数据列建立索引。如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。
  • 频繁更新的字段不适合创建索引:因为每次更新不单单是更新了记录还会更新索引,加重IO负担
  • Where条件里用不到的字段不创建索引
<think>好的,我现在需要帮助用户解决关于Dify循环实现的问题。首先,我需要明确用户的具体需求。他们提到“dify 循环实现”或“dify 如何处理循环”,但Dify本身可能没有直接称为“循环”的功能,所以需要结合现有文档中的信息来推断可能的解决方案。 根据用户提供的引用内容,Dify工作流中有迭代节点[^1]。这可能类似于编程中的循环结构,用于重复执行某个任务。例如,在处理列表数据或需要多次执行同一操作时,迭代节点可以派上用场。我需要详细解释迭代节点的配置和使用步骤,确保用户能够理解如何设置循环次数或遍历数据集。 另外,用户可能对如何处理循环中的错误或性能问题感兴趣。引用[2]提到在Dify中处理PEM文件的问题,这可能涉及在循环中正确处理数据格式,避免错误积累。需要提醒用户在循环中注意错误处理和资源管理,确保每次迭代的稳定性。 引用[3]中的例子展示了如何结合FastAPI和Selenium进行实时监控并生成GIF,这可能涉及循环截取浏览器内容。虽然Dify本身可能不直接控制这类循环,但可以通过外部脚本或定时任务触发工作流,模拟循环执行。这部分需要说明如何将外部循环机制与Dify结合使用。 接下来,我需要组织回答结构。首先介绍迭代节点的基本概念和配置步骤,然后讨论循环中的数据处理和错误处理,最后补充外部触发循环的方法。同时,生成相关问题以帮助用户进一步探索,比如优化循环性能或处理复杂数据结构。 需要确保回答符合格式要求,使用正确的中文表达,行内公式用$...$,独立公式用$$...$$,但当前问题不涉及数学公式,所以可能不需要使用。同时,引用标识要自然地添加到相关段落末尾,如、[^2]、[^3]。 最后,检查是否有遗漏点,比如Dify的其他循环相关功能或用户可能遇到的常见问题,确保回答全面且易于理解。</think>在Dify中处理循环逻辑主要通过**迭代节点**实现,以下是具体实现方式和应用场景的解析: ### 一、Dify循环实现机制 Dify通过**工作流设计器**中的迭代节点处理循环需求,其核心原理类似编程中的`for循环`。迭代节点可遍历以下数据类型: - 数组列表:`["A","B","C"]` - 字典集合:`{"key1":"value1", "key2":"value2"}` - 数值范围:通过`range()`函数生成序列 配置示例: ```python # 模拟迭代节点的数据输入 input_data = { "dataset": [1,2,3,4,5], "process_logic": "item * 2" # 对每个元素执行乘以2的操作 } ``` ### 二、迭代节点的关键配置步骤 1. **数据源绑定**:将数组/字典类型变量连接到迭代节点的输入端口 2. **循环变量命名**:设定当前元素的变量名(默认为`item`) 3. **子流程设计**:在迭代节点内部构建需要重复执行的逻辑模块 4. **结果聚合**:通过`outputs`收集所有迭代结果,支持数组或对象格式 $$ \text{总耗时} = \sum_{i=1}^{n}(单次迭代时间_i) + 系统开销 $$ ### 三、循环中的特殊处理 1. **错误中断控制**: - 启用`continueOnError`参数可跳过失败迭代 - 通过`try-catch`模块包裹敏感操作 2. **并行优化**: ```python # 伪代码示例 Parallel.forEach(dataset, lambda item: process(item)) ``` 3. **结果过滤**: ```python filtered = filter(lambda x: x%2==0, processed_results) ``` ### 四、应用场景案例 1. **批量文件处理**:遍历存储桶中的文件列表进行格式转换 2. **数据清洗**:对数据库查询结果集进行逐条校验 3. **API轮询**:定时循环调用第三方接口直到满足特定条件
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值