mysql数据库索引创建和使用时的注意项

一、sql查询慢原因: 

https://zhuanlan.zhihu.com/p/62941196

https://zhuanlan.zhihu.com/p/155800578

1.分两种情况讨论

1)之前执行正常 ,突然就慢了

2)一直就很慢

2.分析原因

之前正常执行突然慢了,可能有以下两种情况:

  1. 遇到锁了 请求的资源正好被其他的事务加锁了 所以在等锁释放的过程导致执行慢。
    1. 当我们要执行的这条sql语句,这时这条语句涉及到相关的表同时别人也在使用,并且加锁,这个时候我们拿不到锁,就只能等
      待别人释放锁了; 或者,当表没有锁的时候,但是需要使用的某一行被加锁了,这个时候,也只能等待别人释放锁!
  2. 数据库在刷新脏页:mysql为了提高写的性能 会将修改的操作写入到内存中,当插入一条新数据或者更新数据 会在内存中将对应的字段修改,更新完之后 不是立刻同步持久化到磁盘上的。而是把这些数据写入到redolog 中 也就是说 执行了一个更新操作 将redolog buffer 写入到redo log file 在更新完内存和写完redolog 之后便通知客户端操作成功

一直就很慢,可能有以下两种情况:

  1. 没有用上索引
  2. 字段没有索引 :字段上有索引,但由于自己的疏忽,没有使用索引
  3. 函数操作导致没有用上索引

结论:由于某些原因,导致系统没有走索引,而是走了全表扫描,而这也是导致我们 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 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

原文地址:https://www.cnblogs.com/jingpeng77/p/13549787.html