延迟关联-mysql的一种优化方式

举报
阿柠 发表于 2022/10/08 15:49:48 2022/10/08
【摘要】 索引覆盖查询还是有很多陷阱可能导致无法实现优化,MySQL查询优化器会在执行查询前判断是否有一个索引能进行覆盖,假设索引覆盖了where条件中的字段,但不是整个查询涉及的字段。MySQL5.5或者更早的版本还是会回表获取数据行,尽管这一行可能最终还是会被过滤掉。我们举个栗子:SELECT * FROM products where actor = 'SEAM CARREY'AND title...

索引覆盖查询还是有很多陷阱可能导致无法实现优化,MySQL查询优化器会在执行查询前判断是否有一个索引能进行覆盖,假设索引覆盖了where条件中的字段,但不是整个查询涉及的字段。MySQL5.5或者更早的版本还是会回表获取数据行,尽管这一行可能最终还是会被过滤掉。

我们举个栗子:

举个栗子

SELECT * FROM products where actor = 'SEAM CARREY'
AND title like '%APOLLO%';

像上面这个查询索引是无法覆盖的,有两个原因:

  1. 没有任何索引能够覆盖这个查询。因为查询的结果字段是包括了所有的列,没有任何一个索引是可以覆盖所有的列的。当然,理论上MySQL还是有一个捷径可以利用,就是where语句中的条件是有索引覆盖的。
  2. MySQL不能在索引中执行like操作。这是底层存储引擎API的限制。MySQL5.5和更早的版本只支持在索引中做简单比较操作(例如等于,不等于,大于)。mysql能在索引中做最左前缀匹配的like比较,因为该操作可以转换为简单的比较操作,但是如果是通配符开头的like查询,存储引擎就无法做比较匹配。

也有办法是可以解决我上面说的这两个问题的,那就是需要重写查询并巧妙地设计索引。首先将索引扩展到覆盖是三个数据列(actor,title,prod_id),然后按照如下的方式重写查询。

select * 
from products
join (
	select prod_id
	from products
	where actor = 'SEAM CARREY' AND title like '%APOLLO%';
) AS t1 ON (t1.prod_id=products.prod_id);

我们把这种方式叫做延迟关联,因为延迟了对列的访问。在查询的第一阶段MySQL可以使用覆盖索引,在from子句的子查询中找到匹配的prod_id,然后根据这些prod_id 值在外层查询匹配获取需要的所有列值,虽然无法使用索引覆盖整个查询,但总算比完全无法利用索引覆盖的好。

延时关联,即通过使用覆盖索引查询返回需要的主键,再根据主键关联原表获得需要的数据,尤其在大分页查询的场景下,可以提高查询效率。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。