mysql索引讲解
mysql索引讲解
sql语句的执行效率
不同的sql语句执行的效率差别非常大。执行效率差的sql语句会严重影响系统性能,同时,可能会因为长期持有行级别和表级别的锁,导致其他sql语句陷入持续性等待。
所以在应用一个sql语句的时候,我们要先用explain
命令,解释其是否能高效的完成任务。
explain
命令显示出的执行计划中字段有:
- possible_keys :可能用到的索引;
- key:实际用的索引;
- key_len 索引的长度
- rows 表示扫描的数据行数。
- type 表示数据扫描类型
type字段描述的是找到所需数据的扫描方式,常见的扫描类型的执行效率,从高到低分为:
-
All:全表扫描,未使用任何索引,需要扫描所有数据页,要最大限度避免进行全表扫描。
-
index:全索引扫描,遍历整个索引树,不需要回表(查询字段全在索引中)因此,性能优于 ALL,但依然不理想。
-
range:在索引上执行 范围扫描,范围越小性能越好。
-
ref:使用 非唯一索引 进行查找,可能返回 多条记录。其索引列允许重复值,性能取决于索引区分度(不同值越多性能越好)
-
eq_ref:在 多表 JOIN 查询 中,使用主键或唯一索引进行 一对一匹配,每个 JOIN 操作 只匹配到1条记录,常见于主键关联的 JOIN 查询
-
const:最高效,通过主键或唯一索引定位查询结果,最多返回1条。
索引优化的方案
1、 覆盖索引。
覆盖索引是指查询所需字段 全部包含在索引中,无需回表查询数据页。通过减少磁盘I/O次数显著提升性能。示例:
ALTER TABLE users
ADD INDEX idx_cover_username (username, age, gender);
设置联合索引,通过username,就可以直接查询到用户的年龄和性别。
2、 前缀索引。
使用某个字段中字符串的前几个字符建立索引。可以增加一个索引页中存储的索引值,有效提高索引的查询速度。例如,对邮箱的前7个字段
ALTER TABLE users
ADD INDEX idx_email_prefix (email(7));
3、 主键索引自增
自增主键保证数据 物理有序存储,减少页分裂和碎片。每次插入新记录时,主键值自动递增,保证新数据始终追加到B+树的最右侧叶子节点。
4. 索引下推优化
如果查询语句为,多条件查询且存在联合索引。在存储引擎层提前过滤数据,减少回表次数。
索引失效的场景
虽然建立了高效的索引,但是某些sql语句会导致索引失效,要避免这些情况。
1、 使用左右模糊匹配
2、 在查询中,对索引做了计算、函数、类型转换等操作。会使索引失效,
3、在联合索引中,没有遵循最左优先的方式进行匹配,会导致联合索引失效。因为联合索引是局部有序的。
4、在where的子句中,如果O在OR前的条件列是索引列,在列后的索引列不是索引列。那么就会失效。
所以在查询中,可以尽量使用UNION查询,替代OR。
SELECT * FROM products WHERE category_id = 5
UNION ALL
SELECT * FROM products WHERE price > 1000 AND category_id <> 5;
什么时候创建索引
索引是需要动态维护和存储的,什么样的索引是一个好索引呢?怎么判定是否应该对该字段建立索引?
1、 区分度优先原则。首先要对区分度大的字段建立索引。建立联合索引时,应该把区分度大的放在前边。
区分度计算公式:
SELECT
COUNT(DISTINCT gender)/COUNT(*) AS gender_distinct,
COUNT(DISTINCT mobile)/COUNT(*) AS mobile_distinct
FROM users;
2、经常用于where查询和GROUP BY 和 ORDER BY的字段,这样查询的时候,不需要再做一次排序。
3、不用经常性更新的字段,如果索引字段频繁修改,为了维护B+树,会导致频繁地重建索引。