延迟关联-mysql的一种优化方式
【摘要】 索引覆盖查询还是有很多陷阱可能导致无法实现优化,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%';
像上面这个查询索引是无法覆盖的,有两个原因:
- 没有任何索引能够覆盖这个查询。因为查询的结果字段是包括了所有的列,没有任何一个索引是可以覆盖所有的列的。当然,理论上MySQL还是有一个捷径可以利用,就是where语句中的条件是有索引覆盖的。
- 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)