MySQL的索引优化法则

索引

简介

索引(在MySQL中也叫“键key”)是存储引擎快速找到记录的一种数据结构——《高性能MySQL》

索引是基于数据表中的某一列创建的,索引就是数据结构

既然是数据结构,那索引使用哪种数据结构呢?

在这里插入图片描述

第一种: BTREE
  1. BTREE有较好的时间效率,在查找、删除、插入操作上其时间复杂度都是对数阶,即O(logn)。

  2. 存储在B-树上的数据是有序的。通常创建索引时使用哪种数据结构是由数据库决定,但是有些数据库可以指定使用哪种数据结构创建索引。

第二种: HASH
  1. Hash表的查询效率是非常高的,尤其对比较字符串相等的查询。
  2. Hash索引的原理是,将列值作为hash表的key,而value中保存行的指针。
  3. Hash表是无序的数据结构,很多情况下并不能提高效率。
索引是怎么提高查询效率的呢?

索引的本质上是一个存储列值的数据结构。如果在某列上使用了BTREE索引,那么这些列值在索引中是被排过序的,有序的值是索引能提高查询性能的主要原因。

索引中保存了什么呢?

索引中保存了关联行在表中的位置的指针。也就是说索引除了保存列值之外,还保存了与该列值关联的行在表中的位置信息。

索引类别

普通索引:仅加速查询

唯一索引:加速查询 + 列值唯一(可以有null)

主键索引:加速查询 + 列值唯一(不可以有null)+ 表中只有一个

组合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并

全文索引:对文本的内容进行分词,进行搜索

设计原则

1)适合索引的列是出现在where子句中的列,或者连接子句中指定的列;

2)基数较小的类,索引效果较差,没有必要在此列建立索引;

3)使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样能够节省大量索引空间;

4)不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。在修改表内容的时候,索引会进行更新甚至重构,索引列越多,这个时间就会越长。所以只保持需要的索引有利于查询即可。

基础了解
查看索引:show index from user
基数:单个列唯一键(distict_keys)的数量叫做基数。
回表: 数据库根据索引找到了指定的记录所在行后,还需要根据rowid再次到数据块里取数据的操作。

SQL准备

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `age` int(10) NOT NULL DEFAULT 0,
  `gender` tinyint(2) NOT NULL DEFAULT 0 COMMENT '0:男 1:女',
  `email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `level` int(10) NOT NULL DEFAULT 0,
  `create_time` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_name_age_gender`(`name`, `age`, `gender`) USING BTREE COMMENT '组合索引'
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
    

INSERT INTO `user` VALUES (1, 'zhangsan', 20, 0, '[email protected]', 1, '2000-01-01 00:00:00', '2020-05-06 13:47:29');
INSERT INTO `user` VALUES (2, 'lisi', 10, 1, '[email protected]', 2, '2000-01-01 00:00:00', '2020-05-06 13:47:32');
INSERT INTO `user` VALUES (3, 'wangwu', 30, 0, '[email protected]', 3, '2000-01-01 00:00:00', '2020-05-06 13:47:35');

1.组合索引全值匹配

使用联合索引一个字段
explain select * from user where name = 'zhangsan';

使用联合索引一个字段
explain分析,type为ref,使用索引,效率高。key_len为62,根据key_len计算规则,如果字段类型为varchar(n),并且是utf-8编码格式,则key_len=3n+2,where后使用了name,则key_len=3*20+2=62,证明索引用到了联合索引的
第一个字段name,从ref也可以看到一个const。

使用联合索引二个字段
explain select * from user where name = 'zhangsan' and age = 20

使用联合索引二个字段

使用联合索引三个字段
explain select * from user where name = 'zhangsan' and age = 20 and gender = 0;

使用联合索引三个字段

2.最佳左前缀法则

如果是组合索引,一定要遵循最左前缀法则(where后面的条件需要从索引的最左前列开始并且不跳过索引中的列使用)

(有效索引):explain select * from user where name = 'zhangsan' and age = 20 and gender = 0;
(无效索引):explain select * from user where age = 20 and gender = 0;

注:最左法则指的是我们建的组合索引最左面字段要出现在查询条件中

3.索引列上切忌操作

索引列上计算、使用函数、自动或手动进行类型转换,会导致索引失效,从而使查询转向全表扫描。

(索引有效)explain select * from user where name = 'zhangsan'
(索引失效)explain select * from user where left(name,5) = 'zhang'

4.存储引擎范围条件右边索引列无效

explain select * from user where name = 'zhangsan' and age = 20 and gender = 0;
(三个字段都使用“=”号,都使用了索引)
explain select * from user where name = 'zhangsan' and age  > 20 and gender = 0;
(索引未完全使用,在满足age为“=”号条件时全部索引使用,否则,范围之后的索引失效。)

5.只访问索引的查询尽量使用覆盖索引

explain select name,age from user where name = 'zhangsan' and age = 20 and gender = 0;

覆盖索引
查询时使用了索引,用索引列覆盖查询的*, 叫做覆盖索引。

6.避免(!=或者<>、is null,is not null )的使用

explain select name,age from user where name != 'zhangsan'

在这里插入图片描述
Extra显示Using whre Using index,表示查询的列被索引列覆盖,但是where后面条件未使用索引,说明无法直接通过索引查找查询到符合条件的数据。

7.(like ‘%aaa’)索引失效全表扫描

8.建立索引的列不允许为null

  • 单列索引不存null值,复合索引不存全为null的值,如果列允许为null,可能会得到“不符合预期”的结果集,所以,请使用not null约束以及默认值。
  • IS NULL可以命中索引,IS NOT NULL不能命中索引

9.范围条件查询可以命中索引

1.范围条件有:<、<=、>、>=、between等
2.范围列可以用到索引(联合索引必须是最左前缀),但是范围列后面的列无法用到索引,索引最多用于一个范围列,如果查询条件中有两个范围列则无法全用到索引
3.如果是范围查询和等值查询同时存在,优先匹配等值查询列的索引

自己编写的SQL查询语句,尽量使用EXPLAIN命令分析一下,做一个对SQL性能有追求的程序员,嘿嘿嘿…

如有疑问或不同见解,欢迎留言共同交流,博主看到后会在第一时间回复哦…

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/mrhs_dhls/article/details/105949192