网上有很多关于SQL优化的文章,写的很好,但我觉得不够系统,不方便记忆。结合实际使用的一些经验,对SQL优化的功能点进行梳理、总结,方便大家使用。
查询学生张三的成绩的年纪是否为18岁
优化前:
select * from student where age = 18;
再从查询到的结果种判断是否包含张三
优化后:
select name from student where age = 18 and name = "张三";
查询所有18岁的学生姓名
优化前:
select * from student where age = 18;
优化后:
select name from student where age = 18;
批量插入学生数据
优化前:
##伪代码
for(User u :list){
insert into student(age, name, height, weight) values(#{age}, #{name}, #{height}, #{weight});
}
优化后:
insert into student(age, name, height, weight) values
<foreach collection="list" separator="," index="index" item="item">
(#{age}, #{name}, #{height}, #{weight})
</foreach>
原因:
批量插入性能好,插入效率更高
尽量避免同时修改或删除过多数据,因为会造成cpu利用率过高,从而影响别人对数据库的访问,建议分批操作。
这个不多说,删库跑路 必备技能。
优化前:
select * from student where Date_ADD(updated_time,Interval 7 DAY) >=now();
select * from student where age + 1 = 18;
select * from student where substring(name,1,1) = `z`;
优化后:
select * from student where updated_time >= Date_ADD(NOW(),INTERVAL - 7 DAY);
select * from student where age = 18 - 1;
select * from student where name like = "z%";
原因:
将导致系统放弃使用索引而进行全表扫描。
查询年龄不是18岁的学生
优化前:
select * from student where age != 18;
select * from student where age <> 18;
优化后:
select * from student where age < 18 union all select * from student where age > 18;
原因:
将导致系统放弃使用索引而进行全表扫描。
查询年龄为17和18岁的学生信息
优化前:
select * from student where age = 18 or age = 17;
优化后:
select * from student where age = 18 union all select * from student where age = 17;
原因:
将导致系统放弃使用索引而进行全表扫描。
查询未填写城市的学生
优化前:
select * from student where city is null;
优化后:
select * from student where city = "0";
原因:
不用is null 或者 is not null 不一定不走索引了,这个跟mysql版本以及查询成本有关。把null值,换成默认值,很多时候让走索引成为可能。
查询年龄不是17岁的学生信息
优化前:
select * from student where age not in (17);
优化后:
select * from student a left join (select * from student where age = 17 ) b on a.id = b.id where b.id is null;
原因:
not in 不走索引,建议使用not exsits 和 left join优化语句。
in是把外表和内表作hash连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询。如果查询的两个表大小相当,那么用in和exists差别不大,则子查询表大的用exists,子查询表小的用in。
查询所有不重复的用户年龄
优化前:
select distinct * from student
优化后:
select distinct name from student;
原因:
当查询很多字段时,如果使用distinct,数据库引擎就会对数据进行比较,过滤掉重复数据,然而这个比较,过滤的过程会占用系统资源,cpu时间。
查询身高最高的学生
优化前:
select name from student order by height desc;
优化后:
select name from student order by height desc limit 1;
年龄从大到小,分页查询学生姓名
优化前:
select name,age from student order by age desc limit 1, 20;
优化后:
## #{age}代表上次查询的最小年龄
select name,age from student where age < #{age} order by age desc limit 20;
注意,此处的age字段应为唯一索引,如果不是唯一索引,会出现数据重复的问题。
原因:
当偏移量最大的时候,查询效率就会越低,因为Mysql并非是跳过偏移量直接去取后面的数据,而是先把偏移量+要取的条数,然后再把前面偏移量这一段的数据抛弃掉再返回的。
查询姓名包含张三的学生信息
优化前:
select * from student where name like "%张三%";
优化后:
select * from student where name like "张三%";
原因:
like语句后跟"%%"走不了索引。
like语句的优化方案,我觉得很有必要新写一篇文章,后面会把链接贴过来。
关于该部分的优化,可以参考另一篇文章链接:
模糊查询优化 like语句(已亲测)
select * from student where age = 18;
select height from student order by height;
需要为age 和 height 字段加上索引。
存在索引:
KEY `name_age_height` (`name`, `age`, `height`)
存在下面的查询语句:
select * from student where name = "张三";
select * from student where name = "张三" and age = 18;
select * from student where age = 18;
根据最左匹配原则,上面第三条查询语句,是不会走索引的。
索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。
存在索引:
KEY `height_weight` (`height`, `weight`);
KEY `height` (`height`);
上面第二个索引属于冗余索引,需要删除掉。
若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会 逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
参考链接:
https://zhuanlan.zhihu.com/p/299051996
https://www.cnblogs.com/starcrm/p/12971702.html
https://bbs.csdn.net/topics/397417232?list=1149931
https://zhuanlan.zhihu.com/p/169456404
https://blog.csdn.net/wangji5487/article/details/102701330
http://www.360doc.com/content/19/0131/15/16619343_812364509.shtml