mysql 深入学习三 索引优化一
测试建表
CREATE TABLE `employees` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名', `age` int(11) NOT NULL DEFAULT '0' COMMENT '年龄', `position` varchar(20) NOT NULL DEFAULT '' COMMENT '职位', `hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入职时间', PRIMARY KEY (`id`), KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='员工记录表'; INSERT INTO employees(name,age,position,hire_time) VALUES('LiLei',22,'manager',NOW()); INSERT INTO employees(name,age,position,hire_time) VALUES('HanMeimei', 23,'dev',NOW()); INSERT INTO employees(name,age,position,hire_time) VALUES('Lucy',23,'dev',NOW());
注意: 联合索引:KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE
全值匹配
2.联合索引中利用 ‘name’ 和 ‘age’ 字段索引: key_len = ‘name’字段长度 + 'age'字段长度(int:4字节)
3.联合索引中全部利用 ‘name’ 、‘age’和 ‘position’ 字段索引 : key_len = ‘name’字段长度 + 'age'字段长度+‘position’字段长度 (( 存汉字则长度是 3n + 2 字节) 3n+2)3*20+2
注意:修改索引字段顺序,mysql会优化成定义的联合索引的顺序,尽管不影响使用,但还是建议使用定义的联合索引的顺序
最左前缀法则
错误示例二:未使用name索引,导致其他两个索引失效,整体未使用索引
错误示例二:未使用 ‘name’ 和 ‘age’ 索引,导致 'position' 索引 失效,整体未使用索引
不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
1.此处在 ‘name’索引字段上使用了 left()函数操作,导致不走索引:因为left()函数运算后的值在索引树上不一定能找得到值
2.测试前执行:ALTER TABLE `employees` ADD INDEX `idx_hire_time` (`hire_time`) USING BTREE ; #给hire_time增加一个普通索引:
此处在 ‘hire_time’索引字段上使用了 date()函数操作,导致不走索引
测试后执行:ALTER TABLE `employees` DROP INDEX `idx_hire_time`; #删除hire_time的普通索引
存储引擎不能使用索引中范围条件右边的列
尽量使用覆盖索引(只访问索引的查询(索引列包含查询列)),减少 select * 语句 。(覆盖索引不需要回表查询,只需要在索引表就完成查询了)
使用覆盖索引
未使用覆盖索引
mysql在使用不等于(!=或者<>),not in ,not exists 的时候无法使用索引会导致全表扫描
< 小于、 > 大于、 <=、>= 这些,mysql内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引
is null,is not null 一般情况下也无法使用索引
like以通配符开头('%abc...')mysql索引失效会变成全表扫描操作
注意,‘Lei%’ 走了索引 。区别left(name, 3)的函数情况,因为explain没有对函数做底层优化!毕竟explain并不是真的执行sql语句,只是分析
解决一:那么如何优化 ‘%Lei’ 这种情况呢? 使用覆盖索引
字符串不加单引号索引失效
少用or或in,用它查询时,mysql不一定使用索引,mysql内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引,详见范围查询优化
范围查询优化
测试后添加:ALTER TABLE `employees` DROP INDEX `idx_age`; #age字段删除索引