MySQL-小章节-ICP/MRR/BKA特性

1、ICP

Index Condition Pushdown (ICP)是mysql使用索引从表中检索行数据的一种优化方式,从mysql5.6开始支持,mysql5.6之前,存储引擎会通过遍历索引定位基表中的行,然后返回给Server层,再去为这些数据行进行WHERE后的条件的过滤。mysql 5.6之后支持ICP后,如果WHERE条件可以使用索引,MySQL 会把这部分过滤操作放到存储引擎层,存储引擎通过索引过滤,把满足的行从表中读取出。ICP能减少引擎层访问基表的次数和 Server层访问存储引擎的次数。

  • ICP的目标是减少从基表中读取操作的数量,从而降低IO操作
  • 对于InnoDB表,ICP只适用于辅助索引
  • 当使用ICP优化时,执行计划的Extra列显示Using indexcondition提示
  • 数据库配置 optimizer_switch="index_condition_pushdown=on”;

 

 使用场景举例

辅助索引INDEX (a, b, c)

SELECT * FROM peopleWHERE a='12345' AND b LIKE '%xx%'AND c LIKE '%yy%';

若不使用ICP:则是通过二级索引中a的值去基表取出所有a='12345'的数据,然后server层再对b LIKE '%xx%'AND c LIKE '%yy%' 进行过滤

若使用ICP:则b LIKE '%xx%'AND c LIKE '%yy%'的过滤操作在二级索引中完成,然后再去基表取相关数据

ICP特点:

1.mysql 5.6中只支持 MyISAM、InnoDB、NDB cluster

2.mysql 5.6中不支持分区表的ICP,从MySQL 5.7.3开始支持分区表的ICP

3.ICP的优化策略可用于range、ref、eq_ref、ref_or_null 类型的访问数据方法

4.不支持主建索引的ICP(对于Innodb的聚集索引,完整的记录已经被读取到Innodb Buffer,此时使用ICP并不能降低IO操作)

5.当 SQL 使用覆盖索引时但只检索部分数据时,ICP 无法使用

6.ICP的加速效果取决于在存储引擎内通过ICP筛选掉的数据的比例

2、MRR

MRR 的全称是 Multi-Range Read Optimization,是优化器将随机 IO 转化为顺序 IO 以降低查询过程中 IO 开销的一种手段,这对IO-bound类型的SQL语句性能带来极大的提升,适用于range ref eq_ref类型的查询

MRR优化的几个好处:

1.使数据访问有随机变为顺序,查询辅助索引是,首先把查询结果按照主键进行排序,按照主键的顺序进行书签查找

2.减少缓冲池中页被替换的次数

3.批量处理对键值的操作

在没有使用MRR特性时

第一步 先根据where条件中的辅助索引获取辅助索引与主键的集合,结果集为rest

select key_column, pk_column from tb where key_column=x order by key_column

第二步 通过第一步获取的主键来获取对应的值

for each pk_column value in rest do:
select non_key_column from tb where pk_column=val

使用MRR特性时

第一步 先根据where条件中的辅助索引获取辅助索引与主键的集合,结果集为rest

select key_column, pk_column from tb where key_column = x order by key_column

第二步 将结果集rest放在buffer里面(read_rnd_buffer_size 大小直到buffer满了),然后对结果集rest按照pk_column排序,得到结果集是rest_sort

第三步 利用已经排序过的结果集,访问表中的数据,此时是顺序IO

select non_key_column fromtb where pk_column in (rest_sort)

在不使用 MRR 时,优化器需要根据二级索引返回的记录来进行“回表”,这个过程一般会有较多的随机IO, 使用MRR时,SQL语句的执行过程是这样的:

  • 优化器将二级索引查询到的记录放到一块缓冲区中
  • 如果二级索引扫描到文件的末尾或者缓冲区已满,则使用快速排序对缓冲区中的内容按照主键进行排序
  • 用户线程调用MRR接口取cluster index,然后根据cluster index 取行数据
  • 当根据缓冲区中的 cluster index取完数据,则继续调用过程 2) 3),直至扫描结束

通过上述过程,优化器将二级索引随机的 IO 进行排序,转化为主键的有序排列,从而实现了随机 IO 到顺序 IO 的转化,提升性能

此外MRR还可以将某些范围查询,拆分为键值对,来进行批量的数据查询,如下

SELECT * FROM t WHERE key_part1 >= 1000 AND key_part1 < 2000AND key_part2 = 10000;

表t上有二级索引(key_part1, key_part2),索引根据key_part1,key_part2的顺序排序。

若不使用MRR:此时查询的类型为Range,sql优化器会先将key_part1大于1000小于2000的数据取出,即使key_part2不等于10000,带取出之后再进行过滤,会导致很多无用的数据被取出

若使用MRR:如果索引中key_part2不为10000的元组越多,最终MRR的效果越好。优化器会将查询条件拆分为(1000,1000),(1001,1000),... (1999,1000)最终会根据这些条件进行过滤

相关参数

当mrr=on,mrr_cost_based=on,则表示cost base的方式还选择启用MRR优化,当发现优化后的代价过高时就会不使用该项优化

当mrr=on,mrr_cost_based=off,则表示总是开启MRR优化

SET  @@optimizer_switch='mrr=on,mrr_cost_based=on';

参数read_rnd_buffer_size 用来控制键值缓冲区的大小。二级索引扫描到文件的末尾或者缓冲区已满,则使用快速排序对缓冲区中的内容按照主键进行排序

3、BKA

Batched Key Access (BKA)  提高表join性能的算法。当被join的表能够使用索引时,就先排好顺序,然后再去检索被join的表,听起来和MRR类似,实际上MRR也可以想象成二级索引和 primary key的join

如果被Join的表上没有索引,则使用老版本的BNL策略(BLOCK Nested-loop)

BKA原理

对于多表join语句,当MySQL使用索引访问第二个join表的时候,使用一个join buffer来收集第一个操作对象生成的相关列值。BKA构建好key后,批量传给引擎层做索引查找。key是通过MRR接口提交给引擎的(mrr目的是较为顺序)MRR使得查询更有效率。 

大致的过程如下:

  • BKA使用join buffer保存由join的第一个操作产生的符合条件的数据
  • 然后BKA算法构建key来访问被连接的表,并批量使用MRR接口提交keys到数据库存储引擎去查找查找。
  • 提交keys之后,MRR使用最佳的方式来获取行并反馈给BKA

BNL和BKA都是批量的提交一部分行给被join的表,从而减少访问的次数,那么它们有什么区别呢?

  • BNL比BKA出现的早,BKA直到5.6才出现,而NBL至少在5.1里面就存在。
  • BNL主要用于当被join的表上无索引
  • BKA主要是指在被join表上有索引可以利用,那么就在行提交给被join的表之前,对这些行按照索引字段进行排序,因此减少了随机IO,排序这才是两者最大的区别,但是如果被join的表没用索引呢?那就使用NBL

BKA和BNL标识

Using join buffer (Batched Key Access)和Using join buffer (Block Nested Loop)

相关参数

BAK使用了MRR,要想使用BAK必须打开MRR功能,而MRR基于mrr_cost_based的成本估算并不能保证总是使用MRR,官方推荐设置mrr_cost_based=off来总是开启MRR功能。打开BAK功能(BAK默认OFF):

SET optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

BKA使用join buffer size来确定buffer的大小,buffer越大,访问被join的表/内部表就越顺序。

BNL默认是开启的,设置BNL相关参数:

SET optimizer_switch=’block_nested_loop’

支持inner join, outer join, semi-join operations,including nested outer joins

BKA主要适用于join的表上有索引可利用,无索引只能使用BNL

4、总结

ICP(Index Condition Pushdown)

Index Condition Pushdown是用索引去表里取数据的一种优化,减少了引擎层访问基表的次数和Server层访问存储引擎的次数,在引擎层就能够过滤掉大量的数据,减少io次数,提高查询语句性能

MRR(Multi-Range Read)

是基于辅助/第二索引的查询,减少随机IO,并且将随机IO转化为顺序IO,提高查询效率。

不使用MRR之前(MySQL5.6之前),先根据where条件中的辅助索引获取辅助索引与主键的集合,再通过主键来获取对应的值。辅助索引获取的主键来访问表中的数据会导致随机的IO(辅助索引的存储顺序并非与主键的顺序一致),随机主键不在同一个page里时会导致多次IO和随机读。

使用MRR优化(MySQL5.6之后),先根据where条件中的辅助索引获取辅助索引与主键的集合,再将结果集放在buffer(read_rnd_buffer_size 直到buffer满了),然后对结果集按照pk_column排序,得到有序的结果集rest_sort。最后利用已经排序过的结果集,访问表中的数据,此时是顺序IO。即MySQL 将根据辅助索引获取的结果集根据主键进行排序,将无序化为有序,可以用主键顺序访问基表,将随机读转化为顺序读,多页数据记录可一次性读入或根据此次的主键范围分次读入,减少IO操作,提高查询效率。

Nested Loop Join算法

将驱动表/外部表的结果集作为循环基础数据,然后循环该结果集,每次获取一条数据作为下一个表的过滤条件查询数据,然后合并结果,获取结果集返回给客户端。Nested-Loop一次只将一行传入内层循环, 所以外层循环(的结果集)有多少行, 内存循环便要执行多少次,效率非常差。

Block Nested-Loop Join算法

将外层循环的行/结果集存入join buffer, 内层循环的每一行与整个buffer中的记录做比较,从而减少内层循环的次数。主要用于当被join的表上无索引。

Batched Key Access算法

当被join的表能够使用索引时,就先好顺序,然后再去检索被join的表。对这些行按照索引字段进行排序,因此减少了随机IO。如果被Join的表上没有索引,则使用老版本的BNL策略(BLOCK Nested-loop)。

<think>好的,我现在需要解决用户在知识图谱嵌入模型中遇到的ValueError问题,具体是embeds2的维度应为192,但实际得到了52。首先,我得理解这个错误通常发生在哪里。维度不匹配常见于张量操作,比如矩阵乘法、拼接等步骤。用户提到embeds2,可能是指模型中的某个嵌入层输出维度不符合预期。 首先,我应该考虑模型结构。知识图谱嵌入模型通常涉及实体和关系的嵌入,比如TransE、ComplEx等。这些模型会为每个实体和关系分配嵌入向量。embeds2可能对应于关系或实体的某个部分的嵌入。用户提供的错误显示实际维度是52,而期望是192,这说明某个地方的嵌入维度设置不正确,或者在拼接、组合时出现了问题。 接下来,我需要检查嵌入层的定义。比如,用户可能在代码中定义了嵌入层的维度参数,例如embedding_dim。假设模型需要将实体和关系的嵌入拼接起来,如果实体嵌入是100维,关系嵌入是92维,那么拼接后的维度应该是192。但实际得到52,可能是在定义嵌入层时参数设置错误,或者拼接的顺序和方式有误。 另外,也有可能是在数据预处理阶段,实体或关系的索引被错误处理,导致加载了错误维度的嵌入。例如,如果嵌入层的输入索引超过了预定义的嵌入矩阵大小,可能会引发意外的问题,但这里更可能直接报索引错误,而非维度问题。 用户提供的引用内容中有关于networkx处理图数据的代码,可能他们的知识图谱数据中存在未连接的节点,这些节点被手动添加到图中。但不确定这是否直接影响嵌入维度,除非在模型处理节点时,根据节点的存在与否动态调整嵌入层的大小。不过,这需要更多代码细节才能确定。 可能的解决方案步骤: 1. 检查嵌入层的定义,确认所有嵌入层的输出维度是否正确设置。 2. 检查拼接或组合嵌入向量的代码,确保维度相加正确。 3. 验证输入数据中的实体和关系的数量是否与嵌入层的输入维度匹配。 4. 使用调试工具输出中间变量的形状,定位具体出错的代码行。 例如,假设模型中实体嵌入维度是100,关系嵌入是92,拼接后应为192。如果实际中关系嵌入被错误地设置为52,那么拼接后的结果就是100+52=152,与预期不符。或者可能在某个步骤中错误地切片或选择了部分维度。 另外,如果用户使用的是预定义的模型代码,可能需要检查超参数设置,如嵌入维度是否在配置中被错误修改。 总结可能的原因: - 嵌入层参数设置错误(如embedding_dim误写) - 拼接或合并操作中的维度计算错误 - 数据预处理导致实体或关系数量变化,影响嵌入层输入大小 需要用户检查这些方面,特别是在定义模型层的地方,以及数据流经模型时的维度变化。</think>### 知识图谱嵌入模型维度错误解决方案 #### 问题分析 `ValueError: embeds2 维度应为 192 实际为 52` 表明模型中某个张量的实际维度与预期不一致,通常由以下原因导致: 1. **嵌入层定义错误**:实体/关系的嵌入维度参数设置不正确。 2. **拼接逻辑错误**:多个嵌入向量拼接时维度未对齐。 3. **数据索引错误**:实体或关系的ID映射混乱,导致加载了错误维度的嵌入。 --- #### 逐步解决方案 ##### 1. 检查嵌入层定义 知识图谱嵌入模型中,实体和关系的嵌入层需明确定义维度。例如: ```python # 正确示例:假设实体嵌入维度为100,关系嵌入为92,拼接后为192 entity_embed = nn.Embedding(num_entities, 100) # 实体嵌入 rel_embed = nn.Embedding(num_relations, 92) # 关系嵌入 ``` 若此处参数设为`entity_embed=50, rel_embed=2`,则拼接后维度为52,直接引发错误。需确认参数是否与模型设计一致[^1]。 --- ##### 2. 验证拼接操作 若模型需拼接实体和关系的嵌入向量,需确保维度相加正确: ```python # 正确示例:实体嵌入+关系嵌入=100+92=192 combined = torch.cat([entity_emb, rel_emb], dim=-1) ``` 若代码中误写为`entity_emb[:, :50] + rel_emb`,则实际维度为52。需检查切片、索引或拼接代码。 --- ##### 3. 调试维度变化 在关键步骤插入维度打印语句,定位错误位置: ```python print("实体嵌入维度:", entity_emb.shape) # 应为(batch_size, 100) print("关系嵌入维度:", rel_emb.shape) # 应为(batch_size, 92) combined = torch.cat([entity_emb, rel_emb], dim=-1) print("拼接后维度:", combined.shape) # 应为(batch_size, 192) ``` --- ##### 4. 检查数据预处理 确保实体和关系的ID与嵌入层匹配: ```python # 错误示例:若node_data中存在未正确处理的ID,可能映射到错误嵌入 no_edge_node = set(train_node_data.index).difference(set(G.nodes)) G.add_nodes_from(no_edge_node) # 需确保新增节点的ID在嵌入层范围内[^1] ``` --- #### 常见修复场景 | 场景 | 错误示例 | 修复方法 | |--------------------------|----------------------------------|-----------------------------------| | 嵌入维度参数错误 | `nn.Embedding(100, 50)` → 50维 | 改为`nn.Embedding(100, 100)` | | 拼接维度错误 | `cat([entity_emb[:50], rel_emb])`| 移除切片操作 | | 数据ID超出嵌入层范围 | 节点ID=200但嵌入层大小=150 | 扩展嵌入层或过滤无效ID | --- #### 相关问题 1. **如何选择知识图谱嵌入模型的维度?** 答:通常基于数据规模和任务复杂度,实体/关系维度比例可参考论文(如TransE常用50-200维)[^2]。 2. **如何处理未连接到图的节点?** 答:需将其显式加入图结构并初始化嵌入,如`G.add_nodes_from(no_edge_node)`。 3. **GPU训练速度慢可能的原因?** 答:检查数据加载、模型并行度或梯度计算,如使用`torch.utils.data.DataLoader`的`num_workers`优化。 --- : 引用网络数据处理的代码段,涉及节点嵌入的完整性。 : 用户反馈的GPU训练效率问题,可能影响模型调试效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CN-FuWei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值