Mysql篇主要是纯理论的面试问题与技巧。
主要从以下进行开展:
索引相关问题:
1、Mysql如何定位慢查询?
Mysql慢查询:某个业务查询数据响应时间过长或者与预期响应时间相差大。
表象:页面加载过慢、接口压测响应时间过长(超过1s)
往往在以下查询中会出现:
- 聚合查询
- 多表查询
- 表数据量过大查询
- 深度分页查询
定位方式1:使用开源工具进行定位
调试工具:
- Arthas
运维工具:
- Prometheus
- Skywalking
Skywalking工具
Skywalking工具--追踪功能
定位方式2:MySQL自带慢日志
慢查询日志记录了所有执行时间超过指定参数(long_query time,单位:秒,默认10秒)的所有SQL语句的日志
如果要开启慢查询日志,需要在MySQL的配置文件(/etc/my.cnf)中配置如下信息:
配置完毕之后,通过以下指令重新启动MySQL服务器进行测试,查看慢日志文件中记录的信息/var/lib/mysql/localhost-slow.log.
2、SQL语句执行很慢,如何分析?
往往在以下查询中会出现:
- 聚合查询
- 多表查询
- 表数据量过大查询
- 深度分页查询
前面三种【聚合查询、多表查询、表数据量过大查询】可以通过SQL执行计划查找查询慢的原因
具体操作:可以采用 EXPLAIN 或者 DESC 命令获取 MySQL如何执行 SELECT 语句的信息。如
EXPLAIN
SELECT * FROM asset_brand;
执行计划中关键字段
- possible key: 当前sql可能会使用到的索引
- key: 当前sql实际命中的索引
- key_len: 索引占用的大小
- Extra: 额外的优化建议
- type: 这条sql的连接的类型性能由好到差为【NULL---ALL性能依次变差】
- NULL:查询时没使用表
- SYSTEM:查询系统中的表
- CONST:根据主键查询
- EQ_REF:主键索引查询或唯一索引查询
- REF:索引查询
- RANGE:范围查询
- INDEX:索引树扫描【效率低】
- ALL:全盘扫描【效率最低】
注意:当SQL的索引类型为INDEX或者ALL的时候,则说明这条SQL需要优化了。
回到问题:那这个SQL语句执行很慢,如何分析呢?
可以采用MySQL自带的分析工具 EXPLAIN
- 通过key和key_len检查是否命中了索引(索引本身存在是否有失效的情况)
- 通过type字段查看sql是否有进一步的优化空间,是否存在全索引扫描或全盘扫描
- 通过extra建议判断,是否出现了回表的情况,如果出现了,可以尝试添加索引或修改返回字段来修复
3、了解过索引吗?什么是索引?
索引(index)是帮助MSOL高效获取数据的数据结构(有序)。
在数据之外,数据库系统还维护着满足特定査找算法的数据结构(B+树),这些数据结构以某种方式引用(指向)数据。
这样就可以在这些数据结构上实现高级查找算法这种数据结构就是索引。
衍生问题:索引的底层数据结构了解过嘛?
MySQL的InnoDB引擎采用的B+树的数据结构来存储索引
- 阶数更多,路径更短
- 磁盘读写代价B+树更低,非叶子节点只存储指针,叶子阶段存储数据
- B+树便于扫库和区间查询,叶子节点是一个双向链表
衍生问题:为什么使用B+树而不使用别的数据结构?
B+Tree是在BTree基础上的一种优化,使其更适合实现外存储索引结构,InnoDB存储引擎就是用B+Tree实现其索引结构。
B树与B+树对比【B+树只有在叶子节点存数据,其他节点存的是数据的指针,所以查询效率高】
- 磁盘读写代价B+树更低
- 查询效率B+树更加稳定
- B+树便于扫库和区间查询
4、什么是聚簇索引【聚集索引】与非聚簇索引【二级索引】?
聚簇索引(聚集索引):数据与索引放到一块,B+树的叶子节点保存了整行数据,有且只有一个非聚非聚簇索引(二级索引):数据与索引分开存储,B+树的叶子节点保存对应的主键,可以有多个
聚簇索引【聚集索引】选取规则::
- 如果存在主键、主键索引就是聚集索引。
- 如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引。
- 如果表没有主键或没合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引。
非聚簇索引【二级索引】:即我们自己给表中加的索引。
例如:
ALTER TABLE table_name[表名] ADD INDEX index_name[索引名称] (column_name)[表字段];

什么是回表?
通过二级索引找到对应的主键值,到聚集索引中查找整行数据,这个过程就是回表。
5、什么是覆盖索引?
覆盖索引是指查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到。
- 使用id查询,直接走聚集索引查询,一次索引扫描,直接返回数据,性能高。
- 如果返回的列中没有创建索引,有可能会触发回表查询,尽量避免使用select
衍生问题:Mysql超大分页什么处理?
在数据量比较大时,如果进行limit分页查询,在查询时,越往后,分页查询效率越低。
解决方案:覆盖索引+子查询
因为,当在进行分页查询时,如果执行 limit 9000000,10,此时需要MySQL排序前9000010 记录,仅仅返回9000000-9000010 的记录,其他记录丢弃,查询排序的代价非常大。
优化思路:一般分页查询时,通过创建覆盖索引能够比较好地提高性能,可以通过覆盖索引加子查询形式进行优化。
6、索引的创建原则有哪些?
- 1).数据量较大,且查询比较频繁的表【重要】
- 2).常作为查询条件(where)、排序(order by)、分组(group by)的字段【重要】
- 3).字段内容区分度高
- 4).内容较长,使用前缀索引
- 5).尽量联合索引【重要】
- 6).要控制索引的数量【重要】
- 7).如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它
7、什么情况下索引会失效?
查看失效的方式有:使用EXPLIAN执行计划来分析,一般有一下几种情况:
- 违反最左前缀法则
- 范围查询右边的列,不能使用索引
- 不要在索引列上进行运算操作,索引将失效
- 字符串不加单引号,造成索引失效。(类型转换)
- 以%开头的Like模糊查询,索引失效
8、SQL优化经验
表的设计优化(参考阿里开发手册《嵩山版》)
- 比如设置合适的数值(tinyint、int、bigint)
- 比如设置合适的字符串类型(char和varchar)char定长效率高,varchar可变长度效率低,text等
索引优化:参考第6点索引的创建原则
SQL语句优化
- SELECT语句务必指明字段名称(避免直接使用select*)
- SQL语句要避免造成索引失效的写法
- 尽量用union all代替union union会多一次过滤,效率低
- 避免在where子旬中对字段进行表达式操作
- Join优化 能用innerjoin 就不用left join right join,如必须使用 一定要以小表为驱动内连接会对两个表进行优化,优先把小表放到外边,把大表放到里边。left join 或right join,不会重新调整顺序
主从复制、读写分离
如果数据库的使用场景读的操作比较多的时候,为了避免写的操作所造成的性能影响 可以采用读写分离的架构。读写分离解决的是,数据库的写入,影响了查询的效率。
分库分表
分库分表(Database Sharding)是指将一个大的数据库拆分成多个小的数据库或数据表,以提高数据库的性能、扩展性和管理性。分库分表通常用于处理大数据量、访问量高的应用场景。决定分库分表的依据通常有以下几个方面: