本文主要是基本总结了工作中一些常用的操作,以及不合理的知识操作,在对慢查询进行优化时收集的点梳一些有用的资料和信息,本文适合有一定MySQL基础的理和开发人员。 一、查询索引相关 索引基数:基数是优化数据列所包含的不同值的数量。例如,基本某个数据列包含值1、知识3、点梳7、理和4、查询7、优化3,基本那么它的知识基数就是4。索引的点梳基数相对于数据表行数较高(也就是说,列中包含很多不同的值,重复的值很少)的时候,它的网站模板工作效果最好。如果某数据列含有很多不同的年龄,索引会很快地分辨数据行。如果某个数据列用于记录性别(只有"M"和"F"两种值),那么索引的用处就不大。如果值出现的几率几乎相等,那么无论搜索哪个值都可能得到一半的数据行。在这些情况下,最好根本不要使用索引,因为查询优化器发现某个值出现在表的数据行中的百分比很高的时候,它一般会忽略索引,进行全表扫描。惯用的百分比界线是"30%"。 索引失效原因: 对索引列运算,运算包括(+、-、*、/、!、<>、%、like%_(%放在前面) 类型错误,如字段类型为varchar,亿华云where条件用number。 对索引应用内部函数,这种情况下应该建立基于函数的索引 如select * from template t where ROUND(t.logicdb_id) = 1 此时应该建ROUND(t.logicdb_id)为索引,mysql8.0开始支持函数索引,5.7可以通过虚拟列的方式来支持,之前只能新建一个ROUND(t.logicdb_id)列然后去维护 索引的建立 最重要的是根据业务经常查询的语句尽量选择区分度高的列作为索引,区分度的公式是 COUNT(DISTINCT col) / COUNT(*)。表示字段不重复的比率,比率越大我们扫描的记录数就越少。如果业务中唯一特性最好建立唯一键,一方面可以保证数据的亿华云计算正确性,另一方面索引的效率能大大提高 二、EXPLIAN中有用的信息 基本用法 提高性能的特性 extra字段 1. using filesort:说明MySQL会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL中无法利用索引完成的排序操作称为“文件排序” ,其实不一定是文件排序,内部使用的是快排 2. using temporary: 使用了临时表保存中间结果,MySQL在对查询结果排序时使用临时表。常见于排序order by和分组查询group by 3. using index:表示相应的SELECT操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错。 6. impossible where:WHERE子句的值总是false,不能用来获取任何元组 7. select tables optimized away:在没有GROUP BY子句的情况下基于索引优化MIN/MAX操作或者对于MyISAM存储引擎优化COUNT(*)操作, 不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化 8. distinct:优化distinct操作,在找到第一匹配的元祖后即停止找同样值的操作 注:using filesort,using temporary这两项出现时需要注意下,这两项是十分耗费性能的,在使用group by的时候,虽然没有使用order by,如果没有索引,是可能同时出现using filesort,using temporary的,因为group by就是先排序在分组,如果没有排序的需要,可以加上一个order by NULL来避免排序,这样using filesort就会去除,能提升一点性能。 type字段 三、字段类型和编码 mysql返回字符串长度:CHARACTER_LENGTH方法(CHAR_LENGTH一样的)返回的是字符数,LENGTH函数返回的是字节数,一个汉字三个字节 varvhar等字段建立索引长度计算语句:select count(distinct left(test,5))/count(*) from table; 越趋近1越好 mysql的utf8最大是3个字节不支持emoji表情符号,必须只用utf8mb4。需要在mysql配置文件中配置客户端字符集为utf8mb4。jdbc的连接串不支持配置characterEncoding=utf8mb4,最好的办法是在连接池中指定初始化sql,例如:hikari连接池,其他连接池类似spring.datasource.hikari.connection-init-sql=set names utf8mb4。否则需要每次执行sql前都先执行set names utf8mb4。 msyql排序规则(一般使用_bin和_genera_ci): utf8_genera_ci不区分大小写,ci为case insensitive的缩写,即大小写不敏感, utf8_general_cs区分大小写,cs为case sensitive的缩写,即大小写敏感,但是目前 MySQL版本中已经不支持类似于***_genera_cs的排序规则,直接使用utf8_bin替代。 utf8_bin将字符串中的每一个字符用二进制数据存储,区分大小写。 那么,同样是区分大小写,utf8_general_cs和utf8_bin有什么区别? cs为case sensitive的缩写,即大小写敏感;bin的意思是二进制,也就是二进制编码比较。 utf8_general_cs排序规则下,即便是区分了大小写,但是某些西欧的字符和拉丁字符是不区分的,比如ä=a,但是有时并不需要ä=a,所以才有utf8_bin utf8_bin的特点在于使用字符的二进制的编码进行运算,任何不同的二进制编码都是不同的,因此在utf8_bin排序规则下:ä<>a sql yog中初始连接指定编码类型使用连接配置的初始化命令 四、SQL语句总结 常用的但容易忘的: 锁相关(作为了解,很少用) 共享锁:select id from tb_test where id = 1 lock in share mode; 排它锁:select id from tb_test where id = 1 for update 优化时用到: 强制使用某个索引:select * from table force index(idx_user) limit 2; 禁止使用某个索引:select * from table ignore index(idx_user) limit 2; 禁用缓存(在测试时去除缓存的影响):select SQL_NO_CACHE from table limit 2; 查看状态 SQL编写注意 五、踩坑 六、千万大表在线修改 mysql在表数据量很大的时候,如果修改表结构会导致锁表,业务请求被阻塞。mysql在5.6之后引入了在线更新,但是在某些情况下还是会锁表,所以一般都采用pt工具( Percona Toolkit) 如对表添加索引: 七、慢查询日志 有时候如果线上请求超时,应该去关注下慢查询日志,慢查询的分析很简单,先找到慢查询日志文件的位置,然后利用mysqldumpslow去分析。查询慢查询日志信息可以直接通过执行sql命令查看相关变量,常用的sql如下: -- 查看慢查询配置 -- slow_query_log 慢查询日志是否开启 -- slow_query_log_file 的值是记录的慢查询日志到文件中 -- long_query_time 指定了慢查询的阈值 -- log_queries_not_using_indexes 是否记录所有没有利用索引的查询 SHOW VARIABLES LIKE %quer%; -- 查看慢查询是日志还是表的形式 SHOW VARIABLES LIKE log_output -- 查看慢查询的数量 SHOW GLOBAL STATUS LIKE slow_queries; mysqldumpslow的工具十分简单,我主要用到的是参数如下: 例子:mysqldumpslow -v -s t -t 10 mysql_slow.log.2018-11-20-0500 八、查看sql进程和杀死进程 如果你执行了一个sql的操作,但是迟迟没有返回,你可以通过查询进程列表看看他的实际执行状况,如果该sql十分耗时,为了避免影响线上可以用kill命令杀死进程,通过查看进程列表也能直观的看下当前sql的执行状态,如果当前数据库负载很高,在进程列表可能会出现,大量的进程夯住,执行时间很长。命令如下: --查看进程列表 SHOW PROCESSLIST; --杀死某个进程 kill 183665 如果你使用的sqlyog,那么也有图形化的页面,在菜单栏-工具-显示-进程列表。在进程列表页面可以右键杀死进程。如下所示: 查看进程列表 杀死进程 九、一些数据库性能的思考 在对公司慢查询日志做优化的时候,很多时候可能是忘了建索引,像这种问题很容易解决,加个索引就行了。但是有两种情况就不是简单能加索引能解决了: