1 为什么使用count(*)进行查询
这里,首先你要弄清楚 count() 的语义。count() 是一个聚合函数,对于返回的结果集,一行行地判断,如果 count 函数的参数不是 NULL,累计值就加 1,否则不加。最后返回累计值。所以,count(*)、count(主键 id) 和 count(1) 都表示返回满足条件的结果集的总行数;而 count(字段),则表示返回满足条件的数据行里面,参数“字段”不为 NULL 的总个数。
对于 count(主键 id) 来说,InnoDB 引擎会遍历整张表,把每一行的 id 值都取出来,返回给 server 层。server 层拿到 id 后,判断是不可能为空的,就按行累加。
对于 count(1) 来说,InnoDB 引擎遍历整张表,但不取值。server 层对于返回的每一行,放一个数字“1”进去,判断是不可能为空的,按行累加。
单看这两个用法的差别的话,你能对比出来,count(1) 执行得要比 count(主键 id) 快。因为从引擎返回 id 会涉及到解析数据行,以及拷贝字段值的操作。
对于 count(字段) 来说:
如果这个“字段”是定义为 not null 的话,一行行地从记录里面读出这个字段,判断不能为 null,按行累加;
如果这个“字段”定义允许为 null,那么执行的时候,判断到有可能是 null,还要把值取出来再判断一下,不是 null 才累加。也就是前面的第一条原则,server 层要什么字段,InnoDB 就返回什么字段。
对于count() 来说:
并不会把全部字段取出来,而是专门做了优化,不取值。count() 肯定不是 null,按行累加。看到这里,你一定会说,优化器就不能自己判断一下吗,主键 id 肯定非空啊,为什么不能按照 count() 来处理,多么简单的优化啊。当然,MySQL 专门针对这个语句进行优化,也不是不可以。但是这种需要专门优化的情况太多了,而且 MySQL 已经优化过 count() 了,你直接使用这种用法就可以了。
所以结论是:按照效率排序的话,count(字段)<count(主键id)<count(1) ≈count(),所以我建议你,尽量使用 count()。
参考博客:
https://blog.csdn.net/u010033674/article/details/110633029
mvcc是如何实现的
record的两个隐藏字段,更改的事务id, 和指向undo的隐藏指针, 然后借助于版本链条 再加上readView(4个事务id)
读已提交, 每次select的时候都会生成一个readview
可重复读在第一次select的时候才会生成一个readview
参考博客
https://blog.csdn.net/zzti_erlie/article/details/110454543
mvcc能够解决幻读吗
官方文档写的是可重复读的隔离级别下, 使用next-key 就可以
其实感觉要分读的方式, 如果是不加锁的快照读, 既然都不加锁了, 那就没有问题了
如果是加锁读(update, delete也算) 那么就需要next-key了
参考博客:
https://www.oschina.net/question/4154815_2315824
如何优化sql
1 使用explain ,看是否走索引
最左匹配
2 返回结果尽量少。
explain的作用
explain命令查看优化器如何决定执行查询。
主要作用:
- select 子句的操作顺序(先按id来排序(先高后低), 相同Id, 从高到低)
- 查询的类型(select_type)(区别普通查询,联合查询, 子查询等复杂查询)
- talbe: 数据是哪张表的
- type(表示是走索引查还是全量之类的,走的什么样子的索引)
- possible_keys 可能会使用的索引
- key 实际使用的索引
- ken_len 索引使用的长度
- ref 显示索引的哪一列使用g
- row估算出需要读取的行数
- extra: 重要的额外信息, 注意特别损耗性能的两个情况(比如是否会使用外部的索引排序, 是否使用临时表保存中间结果)
死锁
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象
死锁的特性: 互斥, 请求保持,不可剥夺, 循环等待
Mysql innodb默认开启死锁检测innodb_deadlock_detect,发现之后会回滚权重比较小的事务, 权重可能是由事务修改的行数决定的。
通常高并发下会禁用innodb_deadlock_detect, 依赖innodb_lock_wait_timeout 进行事务回滚。
如何避免死锁:
- 以固定的顺序访问表和行
- 如果业务允许, 大事务拆小
- 同一个事务, 尽量一次锁定所有的资源
- 降低隔离级别
- 给表添加合理的索引
- 能用行锁的情况下就用行锁(这个是现实中遇到的事情)
sql的执行过程
- 负责与客户端的通信,是半双工模式, 连接器用来验证用户
- 缓存, 默认不开启, 高版本8.0已经移除
- 分析器: 对客户端传来的 sql 进行分析,这将包括预处理与解析过程,并进行关键词的提取、解析,并组成一个解析树
- 优化器: 进入优化器说明sql语句是符合标准语义规则并且可以执行。优化器会根据执行计划选择最优的选择,匹配合适的索引,选择最佳的方案。
- 执行器: 执行器会调用对应的存储引擎执行 sql。主流的是MyISAM 和 Innodb。
- 写undolog
- 写redolog
- 写binlog
哪些情况下会有索引但是不使用索引
- 1在列上进行运算或使用函数会使索引失效,从而进行全表扫描
- 2 前导模糊查询不会使用索引
- 3 %李,%李%都会导致全表扫描,非前导模糊查询可以使用索引
- 4 新版MySQL的or可以命中索引 ,效率从高到低为union,in,or。in和union的效率差别可以忽略不计,建议使用in ,负向条件索引不会使用索引,建议用in
, 负向条件有:!=、<>、not in、not exists、not like 等 - 5 建立索引的列不为NULL