模糊查询下(like)如何使用覆盖索引优化

在MySQL中,like ‘string%’可以用到索引,但是like ‘%string%’却会全表扫描。这个是常识,但真的就没有解决方法了吗?有的,要使用到索引覆盖。

什么叫覆盖索引?

  • 解释一: 就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说查询列要被所使用的索引覆盖。

  • 解释二: 索引是高效找到行的一个方法,当能通过检索索引就可以读取想要的数据,那就不需要再到数据表中读取行了。如果一个索引包含了(或覆盖了)满足查询语句中字段与条件的数据就叫做覆盖索引。

  • 解释三:是非聚集组合索引的一种形式,它包括在查询里的Select、Join和Where子句用到的所有列(即建立索引的字段正好是覆盖查询语句[select子句]与查询条件[Where子句]中所涉及的字段,也即,索引包含了查询正在查找的所有数据)。

总之,不是所有类型的索引都可以成为覆盖索引。覆盖索引必须要存储索引的列,而哈希索引、空间索引和全文索引等都不存储索引列的值,所以MySQL只能使用B-Tree索引做覆盖索引

小试牛刀

CREATE TABLE a1
(
    id INT AUTO_INCREMENT PRIMARY KEY,
    column_name VARCHAR(20),
    column_type VARCHAR(20)
);
CREATE INDEX idx_a1_column_name ON a1(column_name);

语句1:它没有使用到索引(Extra:using where),意味着全表扫描,理论如此,

语句2:它使用了索引范围查找(type=range)(key=idx_a1_column_name),但是它使用索引方式为二级检索(Extra:Using index condition)还是会有一定的性能消耗的,也有解决办法:针对select的列创建联合索引

语句3:它使用了索引覆盖(Extra:Using index)

结论:

  • using index :使用覆盖索引的时候就会出现
  • using where:在查找使用索引的情况下,需要回表去查询所需的数据
  • using index condition:查找使用了索引,但是需要回表查询数据
  • using index & using where:查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据

有实验证明using index & using where要优于using index condition。

小知识点(原理)

1.啥是回表?

上面讲过如果索引的列在select子句中就不需要回表,索引列也是表,如果索引中包括你需要的列,查询结果就找到了,如果没有你需要的列,索引列中有指针指向表记录的行位置,从表中查询列值

2.二级索引篇

聚簇索引:每个InnoDB表具有一个特殊的索引称为聚集索引。如果您的表上定义有主键,该主键索引是聚集索引。如果你不定义为您的表的主键 时,MySQL取第一个唯一索引(unique)而且只含非空列(NOT NULL)作为主键,InnoDB使用它作为聚集索引。如果没有这样的列,InnoDB就自己产生一个这样的ID值,它有六个字节,而且是隐藏的,使其作为聚簇索引。

二级索引:又称辅助索引、非聚集索引(no-clustered index)。b+tree树结构,然而二级索引的叶子节点不保存记录中的所有列,其叶子节点保存的是<健值,(记录)地址>,非叶子节点存放的记录格式为<键值,主键值,地址>。而聚集索引叶子节点保存保存记录中的所有列,非叶子节点保存的是下一层节点地址。

记录的地址一般可以保存两种形式:

1. 记录的物理地址,页号:槽号:偏移量 
2 . 记录的主键值

innodb引擎是索引组织表,所有记录都放在聚集索引里,因此其辅助索引中的记录地址存放的主键的键值。

读操作

通过二级索引查询记录仅能得到主键值,要查询完整的记录还需要再通过一次聚集索引查询,这种查询方式为书签查找(bookmark lookup)。

写操作:

仅当主键发生改变时,才会更新二级索引。

 

### 使用覆盖索引和子查询优化 SQL 查询中 `LIMIT` 子句的性能 #### 覆盖索引的作用 当查询只需要访问索引而不需要回表读取数据时,这种索引被称为覆盖索引。这能显著减少磁盘I/O次数并加快查询速度[^1]。 对于带有 `LIMIT` 的查询语句来说,如果能够构建合适的覆盖索引,则数据库引擎只需遍历少量的数据页就能获取到所需的结果集,从而极大地提高了效率。 #### 构建有效的覆盖索引 为了使 `LIMIT` 查询更高效,在设计索引时应考虑以下几个方面: - **选择合适列作为索引**:优先为那些频繁用于过滤条件(`WHERE`)、排序 (`ORDER BY`) 或者分组 (`GROUP BY`) 的字段创建索引。 - **确保所有涉及的列都在索引里**:为了让某个特定查询成为真正的“覆盖”,即完全依赖该索引来完成整个查询过程而不必再去查找实际表格中的记录,那么这个索引应该包含此查询所涉及到的所有非聚集键值以及任何其他必要的辅助属性列。 例如,假设有一个商品销售明细表 `sales_detail` ,其中包含如下几项重要信息: | id | product_id | sale_date | price | |--|------------|-----------|-------| | ...|... |... |... | 现在要找出最近三天内销量最高的前五名产品及其销售额度。此时就可以针对 `(sale_date DESC,product_id)` 创建复合索引,并将其设为覆盖索引以加速此类带有限制数量返回结果的操作。 ```sql CREATE INDEX idx_sales ON sales_detail(sale_date DESC, product_id); ``` 这样做的好处在于,当执行下面这条SQL命令的时候, ```sql SELECT product_id,SUM(price) AS total_price FROM sales_detail WHERE sale_date >= DATE_SUB(CURDATE(), INTERVAL 3 DAY) GROUP BY product_id ORDER BY SUM(price) DESC LIMIT 5; ``` MySQL可以直接从索引树结构中找到符合条件的产品ID列表,并计算它们各自的总价,而无需再回到原始表去检索具体的价格数值,进而提升了整体处理效能。 #### 利用子查询进一步提升性能 除了合理设置覆盖索例外,还可以借助子查询来改善含有 `LIMIT` 关键字的复杂查询的速度表现。特别是面对多层嵌套或者存在大量重复运算的情况下,适当重构逻辑关系往往可以获得意想不到的效果。 比如上述例子也可以改写成先求得各产品的总金额排名情况,然后再从中筛选出Top N条目;这样做不仅有助于减轻单次扫描的工作量,而且便于后续维护与扩展功能需求。 ```sql WITH ranked_products AS ( SELECT product_id, SUM(price) OVER (PARTITION BY product_id ORDER BY sale_date DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) as cumulative_total, RANK() OVER(ORDER BY SUM(price) DESC) rank_num FROM sales_detail WHERE sale_date >= DATE_SUB(CURDATE(), INTERVAL 3 DAY) ) SELECT product_id,cumulative_total FROM ranked_products WHERE rank_num<=5 ; ``` 这种方法通过窗口函数实现了累积求和的同时完成了初步排序工作,最后仅需简单选取指定范围内的成员即可达成目标。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值