MySQL作为主流的关系型数据库,索引是提升查询性能的关键工具,但索引并非越多越好,遵循合理的建立原则才能最大化发挥其价值,同时避免不必要的性能损耗。

适合建立索引的场景
频繁作为查询条件的字段
如果一个字段经常出现在WHERE子句中,为其建立索引可以大幅减少全表扫描的概率。比如用户表的手机号字段,常被用来查询用户信息,就适合建立索引。
-- 为user表的phone字段建立普通索引 CREATE INDEX idx_user_phone ON user(phone);
关联查询的关联字段
多表关联查询时,关联字段建立索引可以提升关联效率。比如订单表的用户ID字段,常和用户表的主键ID关联,就需要在订单表的user_id字段上建立索引。
-- 为order表的user_id字段建立索引,用于关联查询 CREATE INDEX idx_order_user_id ON `order`(user_id);
排序和分组使用的字段
如果字段经常出现在ORDER BY或GROUP BY子句中,建立索引可以跳过排序步骤,直接利用索引的有序性返回结果。比如商品表的价格字段,常被用来排序查询,适合建立索引。
-- 为product表的price字段建立索引,优化排序查询 CREATE INDEX idx_product_price ON product(price);
区分度高的字段
字段的区分度越高,索引的过滤效果越好。比如性别字段只有男、女两个值,区分度低,建立索引意义不大;而身份证号字段几乎每个值都唯一,区分度极高,适合建立索引。
不适合建立索引的场景
频繁更新的字段
字段如果经常被更新,每次更新都会同步更新索引,会增加写操作的开销。比如用户的最后登录时间字段,每次用户登录都会更新,就不适合建立索引。
表数据量很小的表
全表扫描的成本很低,建立索引反而会增加额外的存储和维护成本,比如只有几十行数据的配置表,不需要建立索引。
区分度极低的字段
比如订单状态字段,只有待支付、已支付、已取消等少数几个值,即使建立了索引,查询时也可能还是需要扫描大量行,索引效果很差。
不常使用的字段
如果一个字段几乎不会出现在查询条件、排序、分组场景中,建立索引只会浪费存储空间,没有实际收益。
索引设计的其他注意事项
- 尽量使用联合索引代替多个单列索引,联合索引可以覆盖更多查询场景,减少索引数量。比如经常用
WHERE a=? AND b=?查询,可以建立(a,b)的联合索引,而不是分别建立a和b的单列索引。 - 联合索引要遵循最左前缀原则,查询条件必须包含联合索引的最左字段,索引才能生效。比如联合索引是(a,b,c),那么查询条件包含a、a和b、a和b和c时索引生效,只包含b或c时索引不生效。
- 索引列尽量不使用函数或表达式,比如
WHERE YEAR(create_time)=2023这种写法,会导致索引失效,应该改成WHERE create_time >= '2023-01-01' AND create_time < '2024-01-01'。 - 主键尽量使用自增的整数类型,避免随机字符串作为主键,可以减少索引页的分裂,提升插入性能。
索引建立原则验证示例
下面通过一个用户表的查询场景,验证索引建立原则的应用:
-- 创建用户表
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
phone VARCHAR(20) NOT NULL,
gender TINYINT NOT NULL,
create_time DATETIME NOT NULL,
last_login_time DATETIME
);
-- 适合建立的索引:phone是高频查询条件,区分度高,建立索引
CREATE INDEX idx_user_phone ON user(phone);
-- 适合建立的索引:经常按create_time排序查询,建立索引
CREATE INDEX idx_user_create_time ON user(create_time);
-- 不适合建立的索引:gender区分度低,不建立索引
-- CREATE INDEX idx_user_gender ON user(gender); -- 不建议执行
-- 不适合建立的索引:last_login_time频繁更新,不建立索引
-- CREATE INDEX idx_user_last_login ON user(last_login_time); -- 不建议执行
遵循以上MySQL索引建立原则,可以在保证查询性能的同时,最小化索引带来的额外开销,让数据库运行更加高效稳定。