准备数据
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`stuno` int(11) NOT NULL,
`name` varchar(20) DEFAULT NULL,
`age` int(3) DEFAULT NULL,
`classId` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_age_classId_name` (`age`,`classId`,`name`)
) ENGINE=InnoDB AUTO_INCREMENT=500001 DEFAULT CHARSET=utf8;
索引失效案例
单标索引失效案例
最左前缀匹配
范围查询索引右边的列失效
EXPLAIN SELECT SQL_NO_CACHE * FROM student
WHERE student.age=30 AND student.classId>20 AND student.name = 'abc' ;
不等于(!= 或者<>)索引失效
以% 开头的无法使用索引, 以% 结尾的可以使用
OR 前后存在非索引的列,索引失效
关联查询子查询
内连接
Left Join
子查询
排序优化
CREATE INDEX idx_age_classid_name ON student (age,classid,NAME);
EXPLAIN SELECT SQL_NO_CACHE * FROM student ORDER BY age,classid;
EXPLAIN SELECT SQL_NO_CACHE * FROM student ORDER BY age,classid LIMIT 10;
EXPLAIN SELECT SQL_NO_CACHE id,age,classid,name FROM student ORDER BY age,classid;
EXPLAIN SELECT SQL_NO_CACHE id,age FROM student ORDER BY age asc,classid desc LIMIT 10;
EXPLAIN SELECT SQL_NO_CACHE * FROM student ORDER BY age desc,classid desc LIMIT 10;
EXPLAIN SELECT SQL_NO_CACHE * FROM student ORDER BY age asc,classid desc LIMIT 10;
Group By 优化
- 几乎和 order by 一样 都能够使用到所有 提高 sort buffer 的大小
limit 优化
EXPLAIN SELECT SQL_NO_CACHE * FROM student LIMIT 100000,10;
EXPLAIN SELECT SQL_NO_CACHE s2.* FROM student s1
INNER JOIN (select id from student ORDER BY id LIMIT 1000,10) s2
on s1.id=s2.id;
优先使用覆盖索引
CREATE INDEX idx_age_name ON student (age,NAME);
show index FROM student;
EXPLAIN SELECT * FROM student WHERE age <> 20;
EXPLAIN SELECT age,NAME FROM student WHERE age <> 20;
前缀索引
alter table teacher add index index2(email(6));
如果我们使用了 前缀索引就无法使用覆盖索引了, 应为列数据不全必须进行回表查询
使用Hash 函数对长度较高的字符串进行构建索引比较好SELECT CRC32('hello'), 这样存储也有一个弊端就是要存储再加上一个字段
索引下推
CREATE INDEX idx_age_name ON student (age,name);
EXPLAIN SELECT * FROM student WHERE age=45 ORDER BY name
EXPLAIN SELECT * FROM student WHERE age=45 and name like '%aa'
- ICP的使用条件:
① 只能用于二级索引(secondary index)
②explain显示的执行计划中type值(join 类型)为 range 、 ref 、 eq_ref 或者 ref_or_null 。
③ 并非全部where条件都可以用ICP筛选,如果where条件的字段不在索引列中,还是要读取整表的记录
到server端做where过滤。
④ ICP可以用于MyISAM和InnnoDB存储引擎
⑤ MySQL 5.6版本的不支持分区表的ICP功能,5.7版本的开始支持。
⑥ 当SQL使用覆盖索引时,不支持ICP优化方法
。
普通索引和 唯一索引的对比
其他优化策略
EXISTS 和 IN的那个效率高
EXPLAIN SELECT id FROM student WHERE id in(select age from student WHERE age = 48)
EXPLAIN SELECT s.id FROM student s WHERE EXISTS(select * FROM student ss WHERE s.id=ss.id)
count(*) ,count(1) 那个效率高
- 首先不考虑非空等音素 count(*) 和 count(1) 执行效率是一样的
- MyISAM 存储引擎 使用表级锁, 底层记录了一个常量是很快的 o (1) 复杂度;
- InnoDB 存储引擎使用行级锁 所以就需要一条一条去累加了, count(*) 和 count(1) 效率一样, 但是不建议使用主键? 为啥呢, 主要是主键它下面存储是数据节点 那么都需要吧数据加载到内存 所以效率低, 使用具体的某个非空的字段可以选择;
count(*
) 和count(1) 底层自动选择一个占用小的二级索引进行统计 , 也就是 key_len
EXPLAIN SELECT SQL_NO_CACHE COUNT(*) FROM student;
EXPLAIN SELECT SQL_NO_CACHE COUNT(1) FROM student;
select(*) 性能影响
limit 1 对优化的影响