优化思路:
开启慢查询日志,查看哪些sql耗时长
查看执行慢的sql的执行计划(为优化提供方向)
优化查询sql(怎么优化)
使用查看问题sql的使用情况(使用方法是啥)
调整操作系统参数优化(怎么调整)
升级服务硬件(什么条件下升级)
慢查询日志
慢查询日志默认关闭的,开启的方法是mysqletc目录下的配置文件中my.cnf文件中修改参数slow_query_log=on或则是slow_query_log=1开启,开启后需要重启mysql。开启后会在var/lib/mysql生成mysql(跟hostname)-slow.log。其中会记录查询时间比较长的sql语句。其中时间比较长可以用long_query_time设置阈值(默认10s),慢查询日志可能重复的数据比较多,有个mysqldumpslow可以对慢查询日志进行排序。
例如:得到按照时间排序的前10条里面含有左连接的查询语句:
mysqldumpslow-st-t10-g"leftjoin"/var/lib/mysql/slow.log
其中-s表示用什么方式进行排序:al平均锁定时间、ar平均返回记录时间、at平均查询时间、c计数、l锁定时间、r返回记录、t查询时间
-t是topn的意思,返回前面多少条的数据
-g后面可以跟正则表达式,大小写不敏感。
最后的慢查询日志的文件路径。
查看执行计划(explain)
explain结果如上,id:表示查询分配的唯一标识符、select_type:查询的类型、table:查询的表、partitions:匹配的分区、type:join类型、possible_keys:此次查询中可能选用的索引、key:此次查询中确切使用到的索引、ref:哪个字段或常数与key一起被使用、rows:显示此查询一共扫描了多少行,这个是一个估计值、filtered:表示此查询条件所过滤的数据的百分比、extra:额外的信息。
id相同执行顺序自上而下;id不同的话,若是有子查询,id会自增,id越大,优先级越高;id相同和不同同时存在,优先级高的先执行,相同的自上而下执行。
select_type
simple表示不需要union操作或者不包含子查询的简单select查询。有连接查询时,外层的查询为simple。
primary一个需要union操作或者含有子查询的select,位于最外层的单位查询的select_type即为primary。
subquery除了from字句中包含的子查询外,其他地方出现的子查询都可能是subquery
union连接的两个select查询,第一个查询是dervied派生表,除了第一个表外,第二个以后的表select_type都是union
unionresult包含union的结果集,在union和unionall语句中,因为它不需要参与查询,所以id字段为null
dependentunion与union一样,出现在union或unionall语句中,但是这个查询要受到外部查询的影响
dependentsubquery与dependentunion类似,表示这个subquery的查询要受到外部表查询的影响
derivedfrom字句中出现的子查询,也叫做派生表,其他数据库中可能叫做内联视图或嵌套select
table
查询的表名,有如下几种情况:如果查询使用了别名,那么这里显示的是别名如果不涉及对数据表的操作,那么这显示为null如果显示为尖括号括起来的就表示这个是临时表,后边的N就是执行计划中的id,表示结果来自于这个查询产生。如果是尖括号括起来的unionM,N,也是一个临时表,表示这个结果来自于union查询的id为M,N的结果集。
partitions
分区表(对于非分区表值为null)。5.7之后的版本默认会有partitions和filtered两列,但是5.6版本中是没有的,需要使用explainpartitionsselect……来显示带有partitions的列,使用explainextendedselect……来显示带有filtered的列。
type(可以看到sql有哪些问题)
显示的是单位查询的连接类型或者理解为访问类型,访问性能依次从好到差:
system(系统表,特殊的const)
const:使用唯一索引或者主键,返回记录一定是1行记录的等值where条件时,通常type是const。
eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描
ref:非唯一性索引扫描,返回匹配某个单独值的所有行,本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体。
fulltext:全文索引检索,要注意,全文索引的优先级很高,若全文索引和普通索引同时存在时,mysql不管代价,优先选择使用全文索引
ref_or_null:与ref方法类似,只是增加了null值的比较。实际用得不多。
unique_subquery:用于where中的in形式子查询,子查询返回不重复值唯一值
index_subquery用于in形式子查询使用到了辅助索引或者in常数列表,子查询可能返回重复值,可以使用索引将子查询去重。
range:用于in形式子查询使用到了辅助索引或者in常数列表,子查询可能返回重复值,可以使用索引将子查询去重。
index_merge:表示查询使用了两个以上的索引,最后取交集或者并集,常见and,or的条件使用了不同的索引,官方排序这个在ref_or_null之后,但是实际上由于要读取所个索引,性能可能大部分时间都不如range
index:select结果列中使用到了索引,type会显示为index
all:select结果列中使用到了索引,type会显示为index
最少得到range这个值,all最差,代表全表扫描。all之上都可用索引。
possible_keys:此次查询中可能选用的索引,一个或多个;
key:查询真正使用到的索引,select_type为index_merge时,这里可能出现两个以上的索引,其他的select_type这里只会出现一个。
key_len:key_len越小索引效果越好。计算where条件后的,跟查询字段没关系。
ref:如果是使用的常数等值查询,这里会显示const;如果是连接查询,被驱动表的执行计划这里会显示驱动表的关联字段;如果是条件使用了表达式或者函数,或者条件列发生了内部隐式转换,这里可能显示为func
rows:这里是执行计划中估算的扫描行数,不是精确值(InnoDB不是精确的值,MyISAM是精确的值,主要原因是InnoDB里面使用了MVCC并发机制)
filtered:filtered列指示将由mysqlserver层需要对存储引擎层返回的记录进行筛选的估计百分比,也就是说存储引擎层返回的结果中包含有效记录数的百分比。最大值为,这意味着没有对行进行筛选。值从减小表示过滤量增加。rows显示检查的估计行数,rows×filtered显示将与下表联接的行数。例如,如果rows为0,filtered为50.00(50%),则要与下表联接的行数为0×50%=。
extra:这个列包含不适合在其他列中显示单十分重要的额外的信息。
优化查询sql
1、索引优化
为搜索字段(where中的条件)、排序字段、select查询列,创建合适的索引,不过要考虑数据的业务场景:查询多还是增删多?
尽量建立组合索引并注意组合索引的创建顺序,按照顺序组织查询条件、尽量将筛选粒度大的查询条件放到最左边。
尽量使用覆盖索引,SELECT语句中尽量不要使用*。
orderby、groupby语句要尽量使用到索引
索引长度尽量短,短索引可以节省索引空间,使查找的速度得到提升,同时内存中也可以装载更多的索引键值。
太长的列,可以选择建立前缀索引
索引更新不能频繁,更新非常频繁的数据不适宜建索引,因为维护索引的成本。
orderby的索引生效,orderby排序应该遵循最佳左前缀查询,如果是使用多个索引字段进行排序,那么排序的规则必须相同(同是升序或者降序),否则索引同样会失效。
2、LIMIT优化
如果预计SELECT语句的查询结果是一条,最好使用LIMIT1,可以停止全表扫描
处理分页会使用到LIMIT,当翻页到非常靠后的页面的时候,偏移量会非常大,这时LIMIT的效率会非常差。LIMITOFFSET,SIZE;LIMIT的优化问题,其实是OFFSET的问题,它会导致MySql扫描大量不需要的行然后再抛弃掉。解决方案:单表分页时,使用自增主键排序之后,先使用where条件idoffset值,limit后面只写rows;
3、其他查询优化
小表驱动大表,建议使用leftjoin时,以小表关联大表,因为使用join的话,第一张表是必须全扫描的,以少关联多就可以减少这个扫描次数。
避免全表扫描,mysql在使用不等于(!=或者)的时候无法使用索引导致全表扫描。在查询的时候,如果对索引使用不等于的操作将会导致索引失效,进行全表扫描;
避免mysql放弃索引查询,如果mysql估计使用全表扫描要比使用索引快,则不使用索引。(最典型的场景就是数据量少的时候);
JOIN两张表的关联字段最好都建立索引,而且最好字段类型是一样的。
WHERE条件中尽量不要使用notin语句(建议使用notexists);
合理利用慢查询日志、explain执行计划查询、showprofile查看SQL执行时的资源使用情况。
使用查看问题sql的使用情况
QueryProfiler是MySQL自带的一种query诊断分析工具,通过它可以分析出一条SQL语句的硬件性能瓶颈在什么地方。Profiler默认关闭,可以在mysql下使用setprofiling=1开启。
开启后可以通过showprofile和showprofiles语句可以展示当前会话(退出session后,profiling重置为0)中执行语句的资源使用情况。
showprofiles:查看已经分析过的sql语句列表;
showprofile:具体某一条sql语句进行分析;
升级服务硬件
1、缓冲区优化
将数据保存在内存中,保证从内存读取数据设置足够大的innodb_buffer_pool_size(总内存的四分之三或则五分之四),将数据读取到内存中。
2、降低磁盘写入次数
对于生产环境来说,很多日志是不需要开启的,比如:通用查询日志、慢查询日志、错误日志
使用足够大的写入缓存innodb_log_file_size(0.25*innodb_buffer_pool_size)
设置合适的innodb_flush_log_at_trx_