mysql聚集索引,辅助索引,联合索引,覆盖索引

本文深入解析数据库中的聚簇索引与非聚簇索引的区别,介绍联合索引及覆盖索引的工作原理,以及如何利用索引来提高查询效率,降低IO操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

聚簇索引:

一张表只能有一个聚簇索引,通常是主键列,在innodb存储引擎中由聚簇索引构成的b+tree其的节点中key就是主键id,叶子节点上存储的就是一行记录的所有字段。

非聚簇索引:

一个表中可以有多个,叶子节点存放的不是一整行数据,而是主键,所以无法命中覆盖索引时会需要通过叶子结点中的主键去聚簇索引的b+tree中再次寻找,也就是常说的非聚簇索引无法命中覆盖索引时会造成两次b+tree的搜索。

联合索引:

就是由多列组成的的索引。遵循最左前缀规则。对where,order by,group by 都生效

覆盖索引:

指从辅助索引中就能获取到需要的记录,而不需要查找聚簇索引中的记录。使用覆盖索引的一个好处是因为辅助索引不包括一条记录的整行信息,所以数据量较聚集索引要少,可以减少大量io操作。

 

聚集索引与辅助索引的区别:

叶子节点是否存放的为一整行数据

最左前缀规则:

假设联合索引由列(a,b,c)组成,则一下顺序满足最左前缀规则:a、ab、abc;selece、where、order by 、group by都可以匹配最左前缀。其它情况都不满足最左前缀规则就不会用到联合索引。

 

order by排序分为file sort和index,后者效率更高

以下情况不会使用index排序

1、检查的行数过多,并且没有使用覆盖索引。
2、使用了多个索引,mysql一次只会采用一个索引。
3、对索引列同时使用了ASC和DESC。 通过where语句将order by中索引列转为常量,则除外。
4、where与order by使用了不同的索引,与第二条类似
5、where或者ORDER BY中索引列使用了表达式(+1,-1这种操作),包括函数表达式。参见第8,9句
6、where 与ORDER BY组合满足最左前缀,但where中使用了范围查询。
7、order by中加入了非索引列,且非索引列不在where中。
8、order by或者它与where组合没有满足索引最左前列。
9、当使用left join,使用右边的表字段排序。

### 如何利用索引优化 MySQL `GROUP BY` 查询性能 #### 使用覆盖索引来加速 `GROUP BY` 当执行带有 `GROUP BY` 的查询时,如果可以创建一个包含所有所需列的联合索引,则数据库引擎可以直接从索引树中读取数据而无需访问实际的数据页。这种技术称为覆盖索引[^2]。 例如,在表 `orders` 中有三列分别是 `customer_id`, `product_name`, 和 `amount` 并且经常按 `customer_id` 进行分组统计销售总额: ```sql CREATE INDEX idx_customer_product_amount ON orders (customer_id, product_name, amount); ``` 这样做的好处是在做如下查询的时候能够显著提高效率: ```sql SELECT customer_id, SUM(amount) AS total_sales FROM orders WHERE order_date BETWEEN 'start-date' AND 'end-date' GROUP BY customer_id; ``` #### 排序与 `GROUP BY` 结合使用 对于既需要排序又需要分组的情况,应该考虑让索引顺序匹配 `ORDER BY` 或者 `GROUP BY` 子句中的字段列表及其方向(升序或降序)。这有助于减少额外的文件排序操作并加快查询速度[^3]。 假设有一个需求是要获取每个客户的最新订单日期以及对应的金额总和: ```sql ALTER TABLE orders ADD INDEX idx_orderdate_custid_amt (order_date DESC, customer_id, amount); SELECT o.customer_id, MAX(o.order_date), SUM(o.amount) FROM orders o GROUP BY o.customer_id ORDER BY o.order_date DESC; ``` 这里定义了一个复合索引 `(order_date DESC, customer_id, amount)` 来支持上述查询的需求。 #### 减少不必要的回表查找 尽可能地使所选索引成为聚集索引或者是能完全满足查询条件的辅助索引,从而避免因缺少某些列而导致的二次查表现象。特别是对于大容量表格而言,过多的随机I/O会严重影响整体性能[^4]。 比如下面的例子展示了如何构建适合特定场景下的索引结构来防止回表: ```sql -- 假设我们总是按照 user_id 分组,并且只关心 count(*) 和 sum(points),那么我们可以建立这样的索引: CREATE INDEX idx_user_points_count ON users(user_id, points); -- 对应的高效查询可能是像这样的形式: SELECT u.user_id, COUNT(*), SUM(u.points) FROM users u GROUP BY u.user_id; ``` 通过合理设计索引策略,可以在很大程度上改善涉及 `GROUP BY` 操作的 SQL 语句的表现效果。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值