一、为什么要对SQL进行优化?
由于业务数据量的增多,SQL的执行效率对程序的运行效率影响增大,此时就需要对SQL进行优化。
二、SQL优化的方法
1.查询sql尽量不要使用select * ,而是具体字段。
节省资源,减少开销。
2.避免在where子句中使用or来连接条件。
反例:
SELECT * FROM user WHERE id=1 OR salary=5000
正例:使用union all把两个sql结果合并。
SELECT * FROM user WHERE id=1union allSELECT * FROM user WHERE salary=5000
使用or可能会使索引失效,从而全表扫描。
对于or没有索引的salary这种情况,假设它走了id的索引,但是走到salary查询条件时,它还得全表扫描。
3.尽量使用数值替代字符串类型
正例:
主键(id):primary key优先使用数值类型int
性别(gender):0代表女,1代表男;数据库没有布尔类型,mysql推荐使用tinyint
因为引擎在处理查询和连接时会逐个比较字符串中的每一个字符,而对于数值型而言只需要比较一次就够了,字符会降低查询和连接的性能,并会增加存储开销。
4.使用varchar代替char
varchar是变长字段,按数据内容实际长度存储,可以节省存储空间;
char按声明大小存储,不足时补空格;
其次对于查询来说,在一个相对较小的字段内搜索,varchar效率更高
5.对查询进行优化,应尽量避免全表扫描,首先考虑在where及order by,group by涉及的列上建立索引。
6.应尽量避免索引失效。
6.1 应尽量避免在where子句中使用or来连接条件,否则将导致引擎放弃使用索引而进行全表扫描。如:select id from t where num=10 or num=20
6.2 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.3 模糊查询也将导致全表扫描
select id from t where name like '%abc%'
6.4 应尽量避免在where子句种对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:select id from t where substring(name,1,3)='abc'
7.提高group by语句效率
反例:先分组,再过滤。
正例:先过滤,再分组。
8.清空表时优先使用truncate
truncate table 比delete速度快,且使用的系统和事务日志资源少。
delete语句每次删除一行,并在事务日志中为所删除的每行记录一项。truncate table通过释放存储表数据所用的数据页来删除数据。
9.表连接不宜太多,索引不宜太多,一般5个以内。
联的表个数越多,编译的时间和开销也就越大。
每次关联内存中都生成一个临时表。
应该把连接表拆成几个较小的几个执行,可读性更高。
10.深度分页问题
反例:select id,name from account limit 100000,10;
正例:select id,name from account where id > 100000 order by limit 10;
详细请看下文链接:
https://blog.csdn.net/qq_43631716/article/details/117172605
11.使用explain分析SQL执行计划
三、执行计划
explain:
使用explain关键字可以模拟优化器执行SQL查询语句,从而知道MYSQL是如何处理自己的SQL语句的。分析自己的查询语句或是表结构的性能瓶颈。
explain作用:
1.表的读取顺序
2.数据读取操作的操作类型
3.哪些索引可以被使用
4.哪些索引可以被实际使用
5.表之间的引用
explain使用:
在select语句之前增加explain关键字,执行查询会返回执行计划的信息,而不是执行SQL
EXPLAIN SELECT * FROM users WHERE id>3
explain出来的信息有12列,分别是:
id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra
概要描述:
1.id:选择标识符
2.select_type:表示查询的类型
3.table:输出结果集的表
4.type:表示表的连接类型
5.possible_keys:表示查询时,可能使用的索引
6.key:表示实际使用的索引
7.key_len:索引字段的长度
8.rows:扫描出的行数(估算的行数)
9.Extra列:附加信息
id:
select识别符,这是select的查询编号
id如果相同,可以认为是一组,从上往下顺序执行,在所有组中,id值越大,优先级越高,越先执行。
SELECT * FROM users u,test t WHERE u.id = t.id
SELECT * FROM users u WHERE u.id = (SELECT id FROM test t WHERE id =1)
select_type:
表示查询中每个select子句的类型
1)SIMPLE(简单SELECT,不使用UNION或子查询等)
2)PRIMARY(子查询中最外层查询,查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)
3)SUBQUERY(子查询中的第一个SELECT,结果不依赖于外部查询)
4)DERIVED(派生表的SELECT,FROM子句的子查询)
5)UNION(UNION中的第二个或后面的SELECT语句)
type:
对表的访问形式,表示MySQL在表中找到所需行的方式,又称“访问类型”。
常用的类型有:system>const>eq_ref>ref>range>index>ALL(从左到右,性能从好到差)
system:
表只有一行记录(等于系统表),平时不会出现,可忽略不计。
const:
表示通过索引一次就找到了,const用于比较primary key或者unique索引。
eq_ref:
唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描。
ref:
非唯一性索引扫描,返回匹配某个单独值的所有行。本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以它应该属于查找和扫描的混合体。
range:
值检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引,一般就是你在where语句中出现了between、<、>、in等查询,这种范围扫描索引比全表扫描要好,因为它只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引。
index:
Full Index Scan,index与ALL区别为index类型只遍历索引树。这通常比ALL快,因为索引文件通常比数据文件小。也就是说,虽然ALL和Index都是读全表,但Index是从索引中读取的,而ALL是从硬盘中读取的。
ALL:
Full Table Scan,将遍历全表以找到匹配的行。
一般来说:得至少保证查询达到range级别,最好能达到ref
possible_keys:
显示可能应用在这张表中的索引,一个或多个。
查询涉及到的字段上,若存在索引,则该索引将被列出,但不一定被查询实际使用。
key:
实际使用的索引。如果为NULL,则没有索引,或者索引失效。
key_len:
表中索引中使用的字节数,可通过该列计算查询中使用的索引长度。在不损失精确度的情况下,长度越短越好。
博主认为以下这篇文章能更好的帮助大家了解认识explain关键字,大家可以看看哟
【最全最详细explain讲解】explain | 索引优化的这把绝世好剑,你真的会用吗?_检查索引的使用情况 expian-CSDN博客