Mysql优化的问题
一:在mysql中,如何定位慢查询
方法一:开源工具
调试工具:Arthas (阿尔萨斯) 查询上线的项目
运维工具:Prometheus、Skywalking (可以检测出哪个接口)
二:mysql自带的慢日志查询
其实mysql中提供了一个慢日志查询的功能,可以在mysql的系统配置文件中开启这个慢日志的功能,并且也可以设置sql执行超过多少时间来记录到一个日志文件当中,我记得我之前的一个项目配置的是2秒,只要sql执行的时间超过2秒就会记录到日志文件当中,我们就可以在日志文件找到执行比较慢的sql了。
那这个sql语句执行的很慢,你是如何优化的呢?
1:如果一条sql语句执行的比较慢的话,我们通常会使用mysql自动的执行计划explain来去查看这条sql的执行情况,比如在这里面可以提供key和key_len检查是否命中了索引,如果本身已经添加了索引,也可以判断索引是否有失效的情况。
2:可以通过type字段查看sql是否有进一步的优化空间,是否存在全索引扫描或全盘扫描
3:可以通过extra来判断,是否出现了回表的情况,如果出现了,可以尝试添加索引或修改返回字段来修复
了解过索引吗?
1:索引是帮助mysql高效获取数据的数据结构,主要用来提高数据检索的效率,降低数据库的IO成本
2:通过索引对数据进行排序,降低数据排序的成本,也降低了CPU的消耗
索引的底层数据结构了解吗?
Mysql默认的存储引擎是innoDB采用了B+树的数据结构来存储索引。
选择B+树的原因:
- 阶数更多、路径更短
- 磁盘读写代价B+树更低,非叶子节点只存储指针,叶子阶段存储数据
- B+树便于扫库和区间查询,叶子节点是一个双向链表
B树和B+树的区别是什么?
- B树中非叶子节点和叶子节点都会存储数据,B+树的所有数据都会出现在叶子节点上,在查询的时候,B+树查找效率更稳定
- 进行范围查询的时候,B+树效率更高,因为B+树都在叶子节点存储,并且叶子节点是一个双向链表
知道什么是回表查询吗?
这个其实和聚集索引和二级索引是有关系的,回表的意思就是通过二级索引找到对应的主键值,然后到聚集索引中查找整行数据。这个过程就是回表。
聚集索引(聚簇索引):数据与索引放到一块,B+树的叶子节点保存整行数据,有且只有一个
二级索引(非聚簇索引):数据与索引分开存储,B+树的叶子节点保存对应的主键,可以有多个。
什么叫覆盖索引?
- 覆盖索引是指select查询语句使用了索引,在返回的列,必须在索引中全部能够找到,如果我们使用id查询,它会直接走聚集索引查询,一次索引扫描,直接返回数据,性能高。
- 如果按照二级索引查询数据的时候,返回的列中没有创建索引,有可能会触发回表查询,尽量避免使用select*,尽量在返回列中都包含添加索引字段。
Mysql超大分页怎么处理?
超大分页一般都是在数据量比较大的时候,我们使用limit分页查询,并且需要对数据进行排序,这个时候效率比较低,我们可以采用覆盖索引和子查询来解决。
先分页查询数据的id字段,绑定id后,再使用子查询来过滤,只查询这个id列表中的数据就可以,因为查询id的时候,走的覆盖索引,所以效率可以提示很多。
索引创建原则有哪些?(创建索引,如何进行优化)
- 这个情况有很多,不过都有一个前提,就是表中的数据要超过10万以上,我们才会创建索引,并且添加索引的字段是查询比较频繁的字段,一般也是作为查询条件,排序字段或分组的字段
- 我们通常创建索引的时候都是会使用复合索引来创建,一条sql的返回值,尽量使用覆盖索引,如果字段的区分度不高的话,我们也会把它放在组合索引后面的字段。
- 如果某一个字段的内容比较长,我们会考虑使用前缀索引来使用,当然并不是所有的字段都要添加索引,这个索引的数量要控制,因为添加索引也会导致新增改的速度变慢。
什么情况下索引会失效?
这种情况出现的也比较多,我说一下自己的经验吧
- 索引在使用的时候没有遵循最左匹配法则
- 模糊查询,如果%号在前面也会导致索引失效,如果在添加索引的字段上进行了运算操作或者类型转换也会导致索引失效。
- 之前我遇到过一个就是,如果使用了复合索引,中间使用了范围查询,右边的条件索引也会失效,所以,通常情况下,如果要判断这个sql是否有索引失效的情况,可以使用explain执行计划来分析。
谈一谈sql优化的经验
如果是直接说sql优化的话,我会从这几个方面考虑,比如:建表的时候、使用索引、sql语句的编写、主从复制、读写分离、还有一个如果是比较大的话可以使用分库分表。
平时对sql语句做过哪些优化?
- 比如使用select语句务必指明字段名称,不要直接select*
- 注意sql语句避免造成索引失效的方法,如果是聚合查询,尽量使用union all代替union,union会多一次过滤,效率比较低。
- 如果是表关联的话,尽量使用innertjoin,不要使用left jion right join,如果必须使用,建议·要以小表为驱动。
事务的特性
事务的特性就是ACID,指的是:原子性、一致性、隔离性、持久性
并发事务带来哪些问题?
在项目开发中,多个事务并发进行是经常发生的,也是必然现象,一般会出现这写问题
- 脏读:当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库当中,这个时候另外一个事务也访问到了这个数据,因为这个数据还没有提交到数据,那么另外一个事务读到的这个数据是脏数据。
- 不可重复读:一个事务先后读取同一个数据,在这个事务还没有结束的时候,另外一个事务也访问了数据,导致可能第一个事务在两次读数据中,出现不同的数据结果
- 幻读:幻读和不可重复读类似,它是当一个事务读取几行数据后,接着另外一个并发事务插入了一些数据,在随后的查询中,第一个事务就发现多了一些之前没有的记录。
怎么解决并非事务带来的问题?
解决这个的方法就是对事务进行隔离
mysql的默认隔离级别是什么?有几种隔离方法?
- 未提交读:解决不了上面说的所有问题,项目中也不适用
- 读已提交:可以解决脏读的问题,但是解决不了不可重复读和幻读
- 可重复读:可以解决脏读和不可重复读,它也是mysql的默认隔离级别
- 串行化:可以解决所有问题,但是由于是让事务串行执行的性能比较低,所以一般使用mysql的默认隔离级别:可重复读
undo log 和 redo log的区别
- redo log日志记录的是数据页的物理变化,服务宕机可用来同步数据
- undo log记录的是逻辑日志,当事务回滚的时候,通过逆操作恢复原来的数据比如我们删除一条数据的时候,就会在undo log日志文件中新增一条delete语句,如果发生回滚就执行逆操作。
- redo log保证了事务的持久性
- undo log保证了事务的原子性和一致性。
主从同步原理
mysql主要复制的核心就是二进制日志,二进制日志记录了所有的DDL语句和DML语句,具体的过程大概是这个样子的:
- Master主库在事务提交时,会把数据变更记录在二进制日志文件Binlog中
- 从库读取主库的二进制日志文件Binlog,写入到从库中继日志Relay Log
- 从库重做中继日志中的事件,将改变反映它自己的数据
分库分表
暂时没有