前言
Sql语句优化是Mysql性能优化的一部分,我们看下常见Sql语句优化及注意的有哪些。
一、查询SQL尽量不要使用select *,而是具体字段
1. 反例
SELECT * FROM user;
2. 正例
SELECT id,name,tel FROM user
说明:
- 只返回需要的字段,节省资源,减少网络开销。
- 可能用到覆盖索引,减少回表,提高查询效率。
二、避免在where子句中使用 or 来连接
1. 反例
SELECT * FROM user WHERE id = 1 OR name = "song"
2、正例
(1)使用union all
SELECT * FROM user WHERE id = 1
UNION ALL
SELECT * FROM user WHERE name = "song"
(2) 或者分开两条sql写
SELECT * FROM user WHERE id = 1
SELECT * FROM user WHERE name = "song"
说明:
- 使用
or
可能会使索引失效,从而导致全表扫描。 - 对于
or
没有索引的name
这种情况,假设它走了id
的索引,但是走到name
查询条件时,它还得全表扫描。 - 也就是说整个过程需要三步:全表扫描+索引扫描+合并。如果它一开始就走全表扫描,直接一遍扫描就搞定。
- 虽然
mysql
是有优化器的,出于效率与成本考虑,遇到or
条件,索引还是可能失效的。
三、where条件中使用默认值代替null
1. 反例
SELECT * FROM user WHERE age IS NOT NULL
2. 正例
SELECT * FROM user WHERE age>0
说明:
- 并不是说使用了
is null
或者is not null
就会不走索引了,这个跟mysql
版本以及查询成本都有关。 - 如果
mysql
优化器发现,走索引比不走索引成本还要高,就会放弃索引,这些条件!=,<>,is null,is not null
经常被认为让索引失效。Mysql计算如果认为使用索引的时间成本高于全表扫描,比如多次回表,于是mysql宁可全表扫描也不愿意使用索引。 - 其实是因为一般情况下,查询的成本高,优化器自动放弃索引的。
- 如果把
null
值,换成默认值,很多时候让走索引成为可能,同时,表达意思也相对清晰一点。
延伸:
is null/is not null本身并不会导致不使用索引。在官方文档里有写:
https://dev.mysql.com/doc/refman/8.0/en/is-null-optimization.html
MySQL can perform the same optimization on col_name IS NULL that it can use
for col_name = constant_value.
For example, MySQL can use indexes and ranges to search for NULL with IS NULL.
意思大致是MySQL可以对col_name IS NULL执行与col_name = constant_value相同的优化。例如,MySQL可以使用索引和范围搜索带有IS NULL。
四、避免在where子句中使用!=或<>操作符
1、反例
SELECT * FROM user WHERE age !=18
SELECT * FROM user WHERE age<>18
说明:
- 使用
!=
和<>
很可能会让索引失效。 - 应尽量避免在
where
子句中使用!=
或<>
操作符,否则引擎将放弃使用索引而进行全表扫描。