前言
一、mysql有哪些'饮鸩止渴'的提高性能的方法?
二、我为什么改了一行数据,锁这么多?
三、幻读是什么,幻读有什么问题?
四、为什么我只查询一行数据,还是这么慢?
五、为什么mysql语句逻辑相同,执行性能却差异很大
六、如何正确的显示随机数据?
我是一个总标题
一、mysql有哪些'饮鸩止渴'的提高性能的方法?
主要导致需要短时间提高性能的情况有三种,我们根据具体的问题提出对应的解决方案
- 短链接风暴,短时间内有大量建立连接的请求,又断开
- mysql里面有一个max_connect的参数,用来控制最大链接数量,如果超过这个数量,就会报 too_money_connect 。一种方法是 调高max_connect。但是这会有风险,因为这个参数就是用来保护mysql的,如果有大量的链接进入,可能会导致大量的cpu资源用在了权限校验上,而导致处理业务逻辑的能力下降。
- 关闭权限验证,这是一个非常有风险的操作,尤其是你的数据库在外网可访问的情况下。mysql增加了只有本机请求可以通过的命令,可见对与关闭权限验证的重视。
- 慢查询
- 没有索引导致
解决方案:创建索引,mysql已经支持线上的DDL操作,如果你的线上库是一主一从,可以现在从库上执行,从库上断开写入redolog然后执行alter。。。 命令,之后切换成主库,然后再在从库上执行 - sql有问题导致
解决方案:使用改写sql的命令,可以将执行的sql模版改写,但是这很可能会产生误伤。 - 没有正确使用索引导致
解决方案:可以通过在命令上添加froce index指定索引,或者也通过重写的方式
- 没有索引导致
- QPS突然增加
- 业务的暴增或者是新业务的问题导致
如果是新业务,且白名单是一个一个加的,在明确后期业务会下掉这个功能或者问题的情况下可以通过,删除白名单的方式来解决。 - 如果你的新业务是通过新的用户权限来链接数据库的,可以通过删除用户权限来直接让那个qps将为0
- 还是上面的重写方法,重写成一个特别简单的sql如:select 1 ,但是极不推荐,因为可能导致后续的所有业务逻辑失败。
- 业务的暴增或者是新业务的问题导致
二、我为什么改了一行数据,锁这么多?
在msyql的默认隔离级别 可重复读级别下的加锁
有 2个原则 2个优化 1个bug
- 原则1: 可重复读的隔离级别下,默认的加锁是next-key lock = 记录锁(Record Lock) + 间隙锁(Gap Lock)。
- 原则2: 只有读到的行才需要加锁
- 优化1: 在等值查询中,如果条件的是主键索引,会退化成行锁
- 优化2: 在等值查询中,会向右查询到第一个不满足的位置才停下来,如果最右边不满足,会退化成间隙锁。(为什么会向右,因为在innodb中,默认有序,找到第一个等值之后,系统不确定是否存在第二个等值的情况,所以系统会继续请求下一个值,知道发现大于要比较的值才停止,那么根据优化2就会出现gap lock锁住了等值和大于等值中间的间隙)
- bug:唯一索引的范围查询会访问到第一个不满足条件的第一个值为止
三、幻读是什么,幻读有什么问题?
幻读是指 在一个session中两次读取数据时,读取到了另一个session插入的数据。
在可重复读的隔离级别下,引入了间隙锁来解决这个问题,间隙锁引入之后,极容易出现两个相同的sql出现死锁的情况:
因为间隙锁之间并不互斥,而是对间隙中插入数据的动作互斥,那么一个线程如果加了间隙锁 另一个也加了。然后就会两个线程谁也写不进去。
如果在读提交的隔离级别下,就不会有间隙锁,但是需要考虑到数据库的内容和binlog的内容不一致的情况。
比如a线程修改了 c=5这条数据的 b =100,而未提交,之后另外两个线程新增了两个c=5的数据,之后a提交了。
那么生成的binlog日志中 最后一条就是 c=5的数据 b全部等于100,就修改了上面所有c=5的数据。当然可以通过修改binlog的记录方式解决。
四、为什么我只查询一行数据,还是这么慢?
- 第一 这条查询语句被MDL锁住。全称:MataDatalock 元数据锁,用来防止查询的时候,被人修改表结构。MDL锁采用先来后到的机制,一旦MDL写锁出现在等待队列中,那么后面所有的读锁都会被阻塞。
- 第二 fluse table语句被其它语句阻塞,而fluse语句又阻塞了我们的查询语句。
- fluse table语句是刷新所有的表,强制关闭重新打开,清理内部缓存,刷新表结构,表数据。
- 如果已经有查询的请求(默认是持有MDL读锁的),那么fluse table会持有写锁等待,那么我们的查询语句也要等待fluse table执行完成才能继续执行
- 第三 被行级锁 锁住
- 第四 查询字段上没有索引,导致全表扫描
- 第五 在这个事务之前启动的一个事务,在这行数据上进行了很多次操作然后提交,导致我们需要通过mvcc多版本控制忘下找很多版本
五、为什么mysql语句逻辑相同,执行性能却差异很大
大概率是因为破坏了索引的有序性,导致没有使用索引。
- 一种是使用了函数,函数计算完之后的值在索引上可能无序,导致优化器走主键索引或者覆盖索引。
- 一种是数据库类型转换 如 utf-8 和utfmb64 由于utfmb64是utf-8的超类,所以执行的时候等于加了类型转换的函数导致无效。其实可以通过避免函数或者该sql不在索引字段上加函数而是再做比较的值上加
六、如何正确的显示随机数据?
msyql返回随机数据的流程是
先把所有数据读到内存中,并给一个权重,然后再根据权重排序 取出前几个作为随机数,所以如果表数据太大,会很慢。
另外rowid就是数据的具体位置,如果有主键 那么主键就是rowid ,如果没有 系统会随机生成