MySQL知识点3
MySQL中建索引时注意事项
-
避免过度索引
索引会占用存储空间,且会降低INSERT、UPDATE、DELETE等写操作的性能(因为索引需要同步更新)。通常只为常用于查询条件(WHERE)、排序(ORDER BY)、连接(JOIN)的字段创建索引。 -
选择合适的字段建立索引
- 优先为区分度高的字段建立索引(如身份证号),区分度低的字段(如性别)不适合建索引。
- 避免为频繁更新的字段建索引,因为索引维护成本高。
- 长字符串建议使用前缀索引(如
INDEX idx_name (name(10))
),平衡索引大小和查询效率。
-
注意联合索引的顺序
联合索引遵循“最左前缀匹配原则”,应将查询中最常作为条件、区分度高的字段放在前面。例如,(a, b, c)
的索引能匹配a
、a AND b
、a AND b AND c
的查询,但无法直接匹配b
或b AND c
的查询。 -
避免索引失效场景
- 索引字段参与计算或函数操作(如
WHERE YEAR(create_time) = 2023
)。 - 使用
NOT IN
、!=
、<>
、IS NOT NULL
等可能导致全表扫描。 - 字符串不加引号(如
WHERE name = 123
会导致类型转换,索引失效)。 - 使用
OR
连接包含非索引字段的条件。
- 索引字段参与计算或函数操作(如
-
考虑索引类型选择
- InnoDB默认使用B+树索引,适用于范围查询和排序。
- 哈希索引适用于精确匹配(如
=
),但不支持范围查询和排序,Memory引擎支持。 - 空间索引用于地理数据类型,全文索引用于文本内容的模糊查询(替代低效的
LIKE '%...%'
)。
-
定期维护索引
- 通过
EXPLAIN
分析查询计划,检查索引是否被有效使用。 - 表数据大量删除后,使用
OPTIMIZE TABLE
重建索引,减少碎片。 - 监控索引使用情况,删除长期未使用的冗余索引(可通过
sys.schema_unused_indexes
视图查询)。
- 通过
-
特殊场景处理
- 小表(数据量少)无需建索引,全表扫描可能更快。
- 临时表或频繁重建的表,索引收益可能低于维护成本。
- 避免对
NULL
值较多的字段建索引,效果有限。
MySQL中的回表是什么?
在MySQL中,回表是指当使用非聚簇索引(二级索引)查询数据时,若索引本身不包含查询所需的全部字段,需要通过索引叶子节点中存储的主键值,再次访问聚簇索引(主键索引)以获取完整数据的过程。
具体过程:
- 非聚簇索引结构:二级索引的叶子节点仅存储索引字段值和对应的主键值,不包含整行数据。
- 查询触发回表:当查询的字段超出二级索引包含的范围时,数据库会先通过二级索引找到匹配记录的主键,再用主键去聚簇索引中查询完整行数据。
示例:
假设有表user(id, name, age)
,id
是主键(聚簇索引),name
是二级索引。
执行SELECT id, name, age FROM user WHERE name = '张三'
时:
- 先通过
name
的二级索引找到'张三'
对应的主键id=10
; - 再通过主键
id=10
查询聚簇索引,获取age
字段的值,完成整个查询。
MySQL中使用索引一定有效吗?如何排查索引效果?
在MySQL中,使用索引不一定总能提升性能,甚至在某些情况下可能导致性能下降。索引的有效性取决于查询场景、数据分布、索引设计等多种因素。
一、索引无效或效果不佳的常见情况
-
数据量过小的表
对于行数极少的表(如几百行),全表扫描的速度可能比走索引更快(索引本身也有IO开销)。 -
索引选择性过低
当索引字段的区分度低(如“性别”字段只有男/女两个值),MySQL可能会判断全表扫描比走索引更高效。 -
索引失效场景
如索引字段参与函数运算、使用OR
连接非索引字段、使用NOT IN
/!=
等操作,可能导致索引失效(详见之前提到的“索引失效场景”)。 -
大量数据更新场景
频繁的INSERT
/UPDATE
/DELETE
会导致索引频繁维护,反而拖慢写操作性能。 -
联合索引顺序不合理
未遵循“最左前缀原则”,导致查询无法命中联合索引的有效部分。
二、如何排查索引效果?
1. 使用EXPLAIN
分析查询计划
EXPLAIN
是排查索引效果的核心工具,通过它可以查看MySQL如何执行查询、是否使用索引、使用了哪个索引等。
用法:在SQL语句前加EXPLAIN
,例如:
EXPLAIN SELECT * FROM user WHERE name = '张三';
关键字段解读:
type
:表示连接类型,性能从好到差依次为system
>const
>eq_ref
>ref
>range
>index
>ALL
。ALL
表示全表扫描(未使用索引),需优化;range
/ref
等表示使用了索引。
key
:实际使用的索引名称,若为NULL
则未使用索引。rows
:MySQL估计需要扫描的行数,值越小越好。Extra
:额外信息,如Using index
表示使用了覆盖索引(无需回表);Using filesort
表示需要额外排序(可能未用到索引排序);Using where; Using index
表示索引有效且覆盖查询。
2. 查看索引使用情况
通过系统视图监控索引是否被实际使用,避免冗余索引:
-- 查看未使用过的索引(需开启performance_schema)
SELECT OBJECT_SCHEMA AS 数据库名,OBJECT_NAME AS 表名,INDEX_NAME AS 索引名
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE INDEX_NAME IS NOT NULL AND COUNT_STAR = 0AND OBJECT_SCHEMA NOT IN ('mysql', 'sys', 'information_schema', 'performance_schema');
3. 对比执行时间
通过SELECT @@profiling = 1;
开启 profiling,或直接对比加索引前后的查询耗时:
-- 开启 profiling
SET profiling = 1;-- 执行查询
SELECT * FROM user WHERE name = '张三';-- 查看执行时间
SHOW PROFILES;
4. 分析数据分布
使用ANALYZE TABLE
更新表的统计信息,帮助MySQL生成更合理的执行计划:
ANALYZE TABLE user;
若数据分布极端(如某字段90%的值都是“1”),即使有索引,MySQL也可能选择全表扫描。