一、sql查询慢原因:
https://zhuanlan.zhihu.com/p/62941196
https://zhuanlan.zhihu.com/p/155800578
1.分两种情况讨论
1)之前执行正常 ,突然就慢了
2)一直就很慢
2.分析原因
之前正常执行突然慢了,可能有以下两种情况:
- 遇到锁了 请求的资源正好被其他的事务加锁了 所以在等锁释放的过程导致执行慢。
- 当我们要执行的这条sql语句,这时这条语句涉及到相关的表同时别人也在使用,并且加锁,这个时候我们拿不到锁,就只能等
待别人释放锁了; 或者,当表没有锁的时候,但是需要使用的某一行被加锁了,这个时候,也只能等待别人释放锁!
- 当我们要执行的这条sql语句,这时这条语句涉及到相关的表同时别人也在使用,并且加锁,这个时候我们拿不到锁,就只能等
- 数据库在刷新脏页:mysql为了提高写的性能 会将修改的操作写入到内存中,当插入一条新数据或者更新数据 会在内存中将对应的字段修改,更新完之后 不是立刻同步持久化到磁盘上的。而是把这些数据写入到redolog 中 也就是说 执行了一个更新操作 将redolog buffer 写入到redo log file 在更新完内存和写完redolog 之后便通知客户端操作成功
一直就很慢,可能有以下两种情况:
- 没有用上索引
- 字段没有索引 :字段上有索引,但由于自己的疏忽,没有使用索引
- 函数操作导致没有用上索引
结论:由于某些原因,导致系统没有走索引,而是走了全表扫描,而这也是导致我们 SQL 语句执行的很慢的原因。
3.针对SQL语句的优化
1、查询语句中尽量不要使用 *
2、尽量减少子查询,使用关联查询(left join,right join,inner join)替代
3、减少使用IN或者NOT IN ,使用exists,not exists或者关联查询语句替代
4、or 的查询尽量用 union或者union all 代替(在确认没有重复数据或者不用剔除重复数据时,union all会更好)
5、合理的增加冗余的字段(减少表的联接查询)
6、增加中间表进行优化(这个主要是在统计报表的场景,后台开定时任务将数据先统计好,尽量不要在查询的时候去统计)
7、建表的时候能使用数字类型的字段就使用数字类型(type,status...),数字类型的字段作为条件查询比字符串的快
8、那些可以过滤掉最大数量记录的条件必须写在WHERE子句的最末尾
建立了索引后,索引列必须出现在where中,否则索引就白白建立了,比如你的id是从1一直到383000,那么你的语句可以写成select * from hr_worktime where id>-1
还有就是,where条件中避免出现!=,or,between,等东西,否则索引实效。
2.建索引注意事项
1)我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。(最左前缀匹配原则)
2)使用短索引。对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的 列,如果在前10 个或20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
3)少用like语句操作。一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。
4)不要在列上进行运算 select * from users where YEAR(adddate)
5)不使用NOT IN和 or,between等操作
NOT IN和 or,between操作都不会使用索引,将进行全表扫描。
https://www.cnblogs.com/tbyang/p/3396211.html
3.sql语句优化
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: select id from t where num=0
3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num=10 or num=20 可以这样查询: select id from t where num=10 union all select id from t where num=20
5.in 和 not in 也要慎用,否则会导致全表扫描,如: select id from t where num in(1,2,3) 对于连续的数值,能用 between 就不要用 in 了: select id from t where num between 1 and 3
6.下面的查询也将导致全表扫描: select id from t where name like '%abc%' 若要提高效率,可以考虑全文检索。
7.如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描: select id from t where num=@num 可以改为强制查询使用索引: select id from t with(index(索引名)) where num=@num
8.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如: select id from t where num/2=100 应改为: select id from t where num=100*2
9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如: select id from t where substring(name,1,3)='abc'--name以abc开头的id select id from t where datediff(day,createdate,'2005-11-30')=0--‘2005-11-30’生成的id 应改为: select id from t where name like 'abc%' select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'
10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。