索引(在MySQL中也叫“键key”)是存储引擎快速找到记录的一种数据结构——《高性能MySQL》
索引是基于数据表中的某一列创建的,索引就是数据结构
BTREE有较好的时间效率,在查找、删除、插入操作上其时间复杂度都是对数阶,即O(logn)。
存储在B-树上的数据是有序的。通常创建索引时使用哪种数据结构是由数据库决定,但是有些数据库可以指定使用哪种数据结构创建索引。
索引的本质上是一个存储列值的数据结构。如果在某列上使用了BTREE索引,那么这些列值在索引中是被排过序的,有序的值是索引能提高查询性能的主要原因。
索引中保存了关联行在表中的位置的指针。也就是说索引除了保存列值之外,还保存了与该列值关联的行在表中的位置信息。
普通索引:仅加速查询
唯一索引:加速查询 + 列值唯一(可以有null)
主键索引:加速查询 + 列值唯一(不可以有null)+ 表中只有一个
组合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并
全文索引:对文本的内容进行分词,进行搜索
1)适合索引的列是出现在where子句中的列,或者连接子句中指定的列;
2)基数较小的类,索引效果较差,没有必要在此列建立索引;
3)使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样能够节省大量索引空间;
4)不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。在修改表内容的时候,索引会进行更新甚至重构,索引列越多,这个时间就会越长。所以只保持需要的索引有利于查询即可。
查看索引:show index from user
基数:单个列唯一键(distict_keys)的数量叫做基数。
回表: 数据库根据索引找到了指定的记录所在行后,还需要根据rowid再次到数据块里取数据的操作。
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');
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;
如果是组合索引,一定要遵循最左前缀法则(where后面的条件需要从索引的最左前列开始并且不跳过索引中的列使用)
(有效索引):explain select * from user where name = 'zhangsan' and age = 20 and gender = 0;
(无效索引):explain select * from user where age = 20 and gender = 0;
注:最左法则指的是我们建的组合索引最左面字段要出现在查询条件中
索引列上计算、使用函数、自动或手动进行类型转换,会导致索引失效,从而使查询转向全表扫描。
(索引有效)explain select * from user where name = 'zhangsan'
(索引失效)explain select * from user where left(name,5) = 'zhang'
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为“=”号条件时全部索引使用,否则,范围之后的索引失效。)
explain select name,age from user where name = 'zhangsan' and age = 20 and gender = 0;
explain select name,age from user where name != 'zhangsan'
Extra显示Using whre Using index,表示查询的列被索引列覆盖,但是where后面条件未使用索引,说明无法直接通过索引查找查询到符合条件的数据。
1.范围条件有:<、<=、>、>=、between等
2.范围列可以用到索引(联合索引必须是最左前缀),但是范围列后面的列无法用到索引,索引最多用于一个范围列,如果查询条件中有两个范围列则无法全用到索引
3.如果是范围查询和等值查询同时存在,优先匹配等值查询列的索引
自己编写的SQL查询语句,尽量使用EXPLAIN命令分析一下,做一个对SQL性能有追求的程序员,嘿嘿嘿…
如有疑问或不同见解,欢迎留言共同交流,博主看到后会在第一时间回复哦…