[TOC]
1.mysql优化总览
1.执行计划
显示的信息有id,select_type,table,type,key,ref等信息
id:如果有子查询,ID的序号会递增(比如id会出现2了),在一组循环中id越大优先级越高,越早被执行
select_type:查询类型,可以理解为执行语句的类型,比如还可以update等。SIMPLE为简单查询,没有其他单位联合的查询,如果有其他单位一起查询,称之为组合查询
table:显示这一行的数据是关于哪张表的
⭐type:这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、 indexhe和ALL,
⭐ ALL 扫描全表数据
⭐index 遍历索引
range 索引范围查找
index_subquery 在子查询中使用 ref
unique_subquery 在子查询中使用 eq_ref
ref_or_null 对Null进行索引的优化的 ref
fulltext 使用全文索引
⭐ ref 使用非唯一索引查找数据
eq_ref 在join查询中使用PRIMARY KEYorUNIQUE NOT NULL索引关联。
⭐ const 使用主键或者唯一索引,且匹配的结果只有一条记录。
system const 连接类型的特例,查询的表为系统表。
ALL最差(全表扫描)
system(性能最好),const的特例:表仅有一行,平时基本不会出现,忽略不计
const数据库最多匹配一行,最优化的,比如查询id为1的那行数据,const直奔id为1的那行,常用于PRIMARY索引的查询,参数rows为1就表示只扫描的一行
possible_keys:显示可能应用在这张表中的索引。如果为空,没有可能的索引。可以为相关的域从WHERE语句中选择一个合适的语句
⭐key: 实际使用的索引。如果为NULL,则没有使用索引。很少的情况下,MYSQL会选择优化不足的索引。这种情况下,可以在SELECT语句中使用USE INDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制MYSQL忽略索引
key_len:使用的索引的长度。在不损失精确性的情况下,长度越短越好
ref:显示索引的哪一列被使用了,如果可能的话,是一个常数
⭐rows:MYSQL认为必须检查的用来返回请求数据的行数
⭐Extra:关于MYSQL如何解析查询的额外信息。坏的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,结果是检索会很慢
Using index 使用覆盖索引
Using where 使用了用where子句来过滤结果集
Using filesort 使用文件排序,使用非索引列进行排序时出现,非常消耗性能,尽量优化。
1.对于排序字段加索引 2.sort_buffer_size修改其值
Using temporary 表示由于排序没有走索引、使用union、子查询连接查询、使用某些视图等原因,因此创建了一个内部临时表
使用了临时表 sql优化的目标可以参考阿里开发手册
1.1 软件上
也就是sql的优化
简单比如索引,
1.查询语句的优化
2.优化子查询
3.使用索引
4.分解表
5.增加中间表
6.增加冗余字段
7.分析表,检查表,优化表
1.1 查询语句优化
我们常常使用explain(describe)分析执行查询语句的执行信息
desc select city,name,age from t where city='杭州' order by name desc limit 1000 ;
查看执行key的信息 ,及rows查询行数来优化
1.2 优化子查询
在MySQL中,尽量使用JOIN来代替子查询.因为子查询需要嵌套查询,嵌套查询时会建立一张临时表,临时表的建立和删除都会有较大的系统开销,而连接查询不会创建临时表,因此效率比嵌套子查询高.
1.3 使用索引
索引是提高数据库查询速度最重要的方法之一,此处记录使用索引的三大注意事项:
- LIKE关键字匹配'%'开头的字符串,不会使用索引.
- OR关键字的两个字段必须都是用了索引,该查询才会使用索引.
- 使用多列索引必须满足最左匹配.
1.4 分解表
对于字段较多的表,如果某些字段使用频率较低,此时应当,将其分离出来从而形成新的表,
1.5 中间表
对于将大量连接查询的表可以创建中间表,从而减少在查询时造成的连接耗时.
1.6 增加冗余字段
类似于创建中间表,增加冗余也是为了减少连接查询.
1.7 分析表,,检查表,优化表
1. 分析表
使用 ANALYZE 关键字,如ANALYZE TABLE user;
- Op:表示执行的操作.
- Msg_type:信息类型,有status,info,note,warning,error.
- Msg_text:显示信息.
2. 检查表:
使用 CHECK关键字,如CHECK TABLE user [option]
option 只对MyISAM有效,共五个参数值:
- QUICK:不扫描行,不检查错误的连接.
- FAST:只检查没有正确关闭的表.
- CHANGED:只检查上次检查后被更改的表和没被正确关闭的表.
- MEDIUM:扫描行,以验证被删除的连接是有效的,也可以计算各行关键字校验和.
- EXTENDED:最全面的的检查,对每行关键字全面查找.
3. 优化表
使用OPTIMIZE关键字,如OPTIMIZE [LOCAL|NO_WRITE_TO_BINLOG] TABLE user;
LOCAL|NO_WRITE_TO_BINLOG都是表示不写入日志.,优化表只对VARCHAR,BLOB和TEXT有效,通过OPTIMIZE TABLE语句可以消除文件碎片,在执行过程中会加上只读锁.
对mysql进行大量增删改操作,磁盘上的空间没有被立即收回(数据空间、索引位),而是等待新的数据来填充空缺
optimize table tab_name
1.2 硬件优化
1.2-1 配置升级
1.配置多核心和频率高的cpu,多核心可以执行多个线程.
2.配置大内存,提高内存,即可提高缓存区容量,因此能减少磁盘I/O时间,从而提高响应速度.
3.配置高速磁盘或合理分布磁盘:高速磁盘提高I/O,分布磁盘能提高并行操作的能力.
1.2-2 优化数据库参数
优化数据库参数可以提高资源利用率,从而提高MySQL服务器性能.MySQL服务的配置参数都在my.cnf或my.ini,下面列出性能影响较大的几个参数.
- key_buffer_size:索引缓冲区大小
- table_cache:能同时打开表的个数
- query_cache_size和query_cache_type:前者是查询缓冲区大小,后者是前面参数的开关,0表示不使用缓冲区,1表示使用缓冲区,但可以在查询中使用SQL_NO_CACHE表示不要使用缓冲区,2表示在查询中明确指出使用缓冲区才用缓冲区,即SQL_CACHE.
- sort_buffer_size:排序缓冲区
1.2-3 分库分表
因为数据库压力过大,首先一个问题就是高峰期系统性能可能会降低,因为数据库负载过高对性能会有影响。另外一个,压力过大把你的数据库给搞挂了怎么办?所以此时你必须得对系统做分库分表 + 读写分离,也就是把一个库拆分为多个库,部署在多个数据库服务上,这时作为主库承载写入请求。然后每个主库都挂载至少一个从库,由从库来承载读请求。
1.2-4 缓存集群
如果用户量越来越大,此时你可以不停的加机器,比如说系统层面不停加机器,就可以承载更高的并发请求。然后数据库层面如果写入并发越来越高,就扩容加数据库服务器,通过分库分表是可以支持扩容机器的,如果数据库层面的读并发越来越高,就扩容加更多的从库。但是这里有一个很大的问题:数据库其实本身不是用来承载高并发请求的,所以通常来说,数据库单机每秒承载的并发就在几千的数量级,而且数据库使用的机器都是比较高配置,比较昂贵的机器,成本很高。如果你就是简单的不停的加机器,其实是不对的。所以在高并发架构里通常都有缓存这个环节,缓存系统的设计就是为了承载高并发而生。所以单机承载的并发量都在每秒几万,甚至每秒数十万,对高并发的承载能力比数据库系统要高出一到两个数量级。所以你完全可以根据系统的业务特性,对那种写少读多的请求,引入缓存集群。具体来说,就是在写数据库的时候同时写一份数据到缓存集群里,然后用缓存集群来承载大部分的读请求。这样的话,通过缓存集群,就可以用更少的机器资源承载更高的并发。
1.3 查询优化
1.3-1 limit分页
select *
from stu
where type = '2020'
order by reg_time
limit 1000,10
给type加上索引,确实能使查询效率变快
但是如果是 limit 1000000000,10
这也会变得很慢
方案
在前端数据浏览翻页,可以将上一页的最大值作为查询条件
select *
from stu
where type = '2020'
and reg_time > '2020-11-24 11:18:00'
order by reg_time
limit 10
1.3-2 limit查改删
select * stu where stu_name = 'summit';
如果stu_name是唯一索引,可以这么写
select * stu where stu_name = 'summit' limit 1;
update stu set stu_name = 'summit' where id = '1' limit 1;
修改操作时,能确定只修改一条,加上limit 1,否则生产update写错,导致大量数据被修改;
1.3-3 超大分页怎么处理?
1.索引覆盖,要查询的所有字段都在索引中,所以速度会很快
select * from table where age > 20 limit 1000000,10
select * from table where id in (select id from table where age > 20 limit 1000000,10)
2.带上上一页的条件比如: id>上一页最大id
LIMIT偏移量大的时候,查询效率较低
可以记录上次查询的最大ID,下次查询时直接根据该ID来查询
1.3-4 优化WHERE子句
多数数据库都是从左往右的顺序处理条件的,把能够过滤更多数据的条件放到前面,把过滤少的条件放在后面
1.3-5 优化子查询
用关联查询替代
优化GROUP BY和DISTINCT
这两种查询据可以使用索引来优化,是最有效的优化方法
关联查询中,使用标识列分组的效率更高
如果不需要ORDER BY,进行GROUP BY时加ORDER BY NULL,MySQL不会再进行文件排序。
WITH ROLLUP超级聚合,可以挪到应用程序处理
1.3-6 优化UNION查询
UNION ALL的效率高于UNION