MySQL面试题——第二篇
1. MySQL的优化手段有哪些?
MySQL的常见的优化手段有以下五种
1. 查询优化
- 避免select * ,只查询需要的字段。
- 小表驱动大表,即小的数据集驱动大的数据集,比如当B表的数据集小于A表时,用in优化exist。两表执行顺序是先查B表,在查询A表,查询语句: select * from A where id in(select id from B)。
- 一些情况下,可以使用连接代替子查询,因为使用join时,MySQL不会在内存中创建临时表。
2. 优化索引的使用
- 尽量使用主键查询,而非其他索引,因为主键查询不会触发回表查询。
- 不做列运算,把计算放入业务系统实现。
- 查询语句尽可能简单,大语句拆小语句,减少锁时间。
- 不使用select * 查询。
- or查询改写成in查询
- 不用函数和触发器
- 避免使用‘%xx’查询
- 少用join查询
- 使用同类型比较,比如‘123’和‘123’、123和123
- 尽量避免在where子句中使用!=或者<>查询引用会放弃索引而进行全表扫描。
- 列表数据使用分页查询,每页数据量不要太大。
- 用exists代替in查询。
- 避免在索引列上使用is null 和is not null。
- 尽量使用主键查询
- 避免在where子句中对字段进行表达式操作。
- 尽量使用数字型字段,若只包含数值信息的字段尽量不要设计为字符型。
3. 表结构设计优化
- 使用可以存下数据最小的数据类型。
- 使用简单的数据类型,int要比varchar类型处理简单。
- 尽量使用tinyint、smallint、mediumint作为整数类型而非int。
- 尽可能使用not null定义字段,因为null占用4字节空间。
- 尽量少用text类型,非用不可时考虑分表。
- 尽量使用timestamp而非datetime。
- 单表不要有太多字段,建议在20个字段以内。
4. 表拆分
当数据库中的数据非常大时,查询优化方案也不能解决查询速度慢的问题时,可以考虑拆分表,让每张表的数据量变小,从而提高查询效率。
- 垂直拆分:把一张列比较多的表拆分为多张表,比如,用户表中一些字段经常被访问,将这些字段放在一张表中,另外一些不常用的字段放在另一张表中。插入数据时,使用事务确保两张表的数据一致性。
- 水平拆分:表的行数超过200w时,就会变慢,这时可以把一张表的数据拆分成多张表来存放。通常情况下,使用取模的方式进行表的拆分。
读写分离
一般来说,数据库都是读多写少,换言之,数据库的压力多数是因为大量的读取数据操作造成的,我们可以使用数据库集群的方案,使用一个库作为主库,负责写入数据;其他库作为从苦,负责读取数据。
2. 主键使用自增id还是UUID
如果是单机的话,选择自增id;如果是分布式系统,优先考虑UUID,但还是最好有一套分布式唯一ID生产方案。
自增ID
:数据存储空间小,查询效率高。但是,不适合分布式场景。
UUID
:适合大量数据的插入和更新操作,但是,他是无序的,插入数据效率慢,占用空间大。
3. 如何优化长难的查询语句
- 将一个大的查询分为多个小的相同的查询
- 减少冗余记录的查询
- 一个复杂查询可以考虑拆分成多个简单查询。
- 分解关联查询,让缓存的效率更高。
4. 一条SQL执行过长的时间,从哪些方面入手优化
- 查看是否涉及多表和子查询,优化SQL结构,去除冗余字段,是否可拆表等。
- 优化索引结构,看是否可以适当添加索引
- 数量大的表,可以考虑进行 分表
- 数据库主从分离,读写分离
- explain分析sql语句,查看执行计划,优化SQL
- 查看MySQL执行日志,分析是否有其他方面问题。
5. 如果某个表有近千万行数据,CRUD比较慢,如何优化
- 分表分库
某个表有近千万数据,可以考虑优化表结构,分表(水平分表、垂直分表)。- 索引优化
6. 如何删除百万级别或以上的数据
- 删除百万数据的时候可以先删除索引
- 批量删除其中无用数据
- 删除完成后重新添加索引。
7. MySQL有哪些重要的日志文件
1. 错误日志:
用来记录MySQL服务器运行过程中的错误信息
2. 查询日志:
查询日志在MySQL中被称为通用日志,查询日志中记录了数据库执行的所有命令。如果不是在调试环境中,不建议开启查询日志功能,否则日志会非常大,影响MySQL性能。
3. 慢日志:
慢查询会导致CPU、内存消耗过高,当数据库遇到瓶颈时,大部分时间都是由于慢查询导致的。开启慢查询日志,可以让MySQL记录下查询超过指定时间的语句。
4. redo log(重做日志):
为了最大程度的避免数据写入时,因为IO瓶颈造成的性能问题,MySQL采用了一种缓存机制,先将数据写入内存中,再批量把内存中的数据统一刷回磁盘。为了避免将数据刷回磁盘过程中,因为掉电或者系统故障带来的数据丢失,InnoDB采用redo log来解决此问题。
5. undo log(回滚日志)
:用于存储日志被修改前的值,从而保证如果修改出现异常,可以使用undo log日志来实现回滚。undo log和redo log记录物理日志不一样,他是逻辑日志,可以认为,当delete一条记录时,undo log中会记录一条相反的insert 记录,update一条记录时,记录一条对应的相反的update记录。当执行rollback时,就可以从undolog中的逻辑记录读取到相应的内容并进行回滚。
undo log默认存放在共享表空间中,在MySQL5.6后,undo log存放位置还可以设置在自定义目录。
6. binlog(二进制日志)
:二进制文件,主要记录所有数据库表结构变更,比如create、alter等,以及表数据修改,比如,insert、update、delete等,binlog中记录了对mysql数据库执行更改的所有操作,并且记录了语句发生时间,执行时长,操作数据等信息。
8. MySQL的binlog有几种格式,分别有什么区别
有三种格式:statement、row和mixed
statement
:每一条会修改数据的SQL
都会记录在binlog中,不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能,由于SQL执行是有上下文的,因此在保存的时候需要保存相关信息,同时,使用了函数之类的语句无法被记录复制。
row
:不记录SQL语句上下文相关信息,仅保存哪条记录被修改,记录单元为每一行的改动,基本是可以全部记下来但是由于很多操作,会导致大量行的改动,因此,这种模式的文件保存的信息太多,日志量太大。
mixed
:一种折中的方案,普通操作使用statement记录,当无法使用statement的时候使用row。
9. redo log 和binlog有什么区别
redo log 和 binlog 都是MySQL的重要日志,区别如下:
- redo log是物理日志,记录的是【在某个数据页上做了修改】
- bin log是逻辑日志,记录的是这个语句的原始逻辑,比如【给ID=2这一行c字段加1】
- redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用。
redo log是循环写的,空间固定会用完,binlog是追加写入的,追加写是指binlog文件写到一定大小会切换到下一个,并不会覆盖以前的日志。
最开始MySQL里没有InnoDB引擎,MySQL自带的引擎是MyISAM,但是MyISAM没有crash-safe能力,binlog只能用于归档,而InnoDB是另一个公司以插件形式引入MySQL的,既然只依靠binlog是没有crash-safe能力的,所以InnoDB使用另外一套日志系统,也就是redo log实现crash-safe。
10. 什么是脏页和干净页
MySQL为了操作的性能优化,把数据更新先放入内存中,之后在统一更新到磁盘,当内存数据和磁盘数据不一致的时候,称这个内存页为脏页;内存数据写到磁盘后,内存的数据和磁盘上的内容就一致了,我们称为【干净页】。
11. 什么情况下会引发MySQL刷脏页的操作
- 内存写满了,这个时候就会引发flush操作,对应到InnoDB就是redo log写满了。
- 系统内存不足了,当需要新的内存页的时候,就会淘汰一些内存页,如果淘汰的是脏页这个时候就会触发flush操作。
- 系统空闲的时候,MySQL会同步内存中的数据到磁盘也会触发flush操作。
- MySQL服务关闭的时候也会刷脏页,触发flush操作。
12. MySQL刷脏页很慢可能是什么原因
在MySQL中单独刷一个脏页速度是很快的,如果发现刷脏页速度很慢,说明触发了MySQL刷脏页的【连坐】机制,MySQL【连坐】机制指当MySQL刷脏页的时候如果发现相邻的数据页也是脏页也会一起刷掉,而这个动作会一直蔓延下去。
13.事务执行期间还未提交,如果发生crash,redolog 丢失,是否会导致主备不一致
不会,因为这时候binlog也还在binlog cache里,没发给备库,crash以后redo log和binlog都没有了,从业务角度看这个事务没有提交,所以数据是一致的。
14. 在MySQL中用什么机制来优化随机读/写磁盘对IO的消耗
redo log是用来节省随机写磁盘的IO消耗,而change buffer主要是节省随机读磁盘的IO消耗,redo log会把MySQL的更新操作先记录到内存中,之后统一更新到磁盘,而change buffer是把关键查询数据先加载到内存中,以便优化MySQL 查询。
15. 如何将MySQL的数据恢复到过去某个指定的时间点
例如,今早九点,想把数据恢复成早上六点的状态,这个时候可以先把0点备份的数据库文件,还原到测试库,再从binlog文件中依次取出0:00到6:00的操作信息,重放binlog,就可以完成数据库的还原。
16. 读写分离会带来什么问题?如何解决?
读写分离带来的问题,主要包括
数据一致性问题、延迟问题、负载均衡问题、故障恢复问题
。
1. 数据一致性问题
- 问题:由于读写分离会导致数据再不同的数据库副本之间不同步,从而导致读到陈旧数据问题。
- 解决方法:
使用主从复制:通过配置异步复制、半同步复制或者全同步复制保证数据及时同步到从库。
读写分配策略:关键操作从主库读取,非关键数据从从库读取。
2. 延迟问题
- 问题:主从复制通常存在一定的延迟,特别是在数据写入频繁的场景下,从库的延迟可能会导致读到过期的数据。
- 解决方法:
同步复制:虽然会影响性能,但可以确保数据的一致性。
提高硬件性能:通过提升服务器硬件性能、优化网络带宽和配置高效的存储设备来减少复制延迟。
优化复制机制:使用增量复制或者并行复制技术加快复制速度。
3. 负载均衡问题
- 问题:读写分离后,如何有效的分配读请求到多个从库,确保负载均衡也是一个挑战
- 解决方法:
负载均衡器:使用专门的负载均衡器来分配请求。
数据库代理
自定义策略
4. 故障恢复问题
- 当主库或从库出现故障时,如何迅速恢复。
- 解决方法
主从切换:主库故障时,迅速将从库提升为主库。
自动化运维:使用自动化运维工具来监控和管理主从切换。
数据备份和恢复:定期进行数据备份,确保数据在故障发生时能够迅速恢复。
17. 主从复制原理是什么
MySQL binlog主要记录了MySQL数据库中数据的所有变化(数据库执行的所有DDL和DML语句),因此,根据主库的MySQL binlog日志就能够将主库的数据同步到从库。
具体流程如下:
- 主库将数据库中数据的变化写入到binlog。
- 从库连接主库。
- 从库会创建一个IO线程向主库请求更新的binlog。
- 主库会创建一个binlog dump线程发送binlog,从库中的IO线程负责接收。
- 从库的IO线程将接收的binlog写入到relay log中。
- 从库的SQL线程读取relay log同步数据到本地。
18. 分库分表会带来什么问题
join操作
:同一个数据库中的表分布在了不同的数据库中,导致无法使用join操作,这样就导致需要手动进行数据的封装,比如在一个数据库中查询到数据之后,在根据这个数据去另一个数据库中找对应的数据。
事务问题
:单个操作涉及到多个数据库,那么数据库自带的事务就无法满足需求。
分布式ID
:需要为不同的数据节点生成全局唯一主键。
原文地址:https://blog.csdn.net/weixin_42824596/article/details/142360086
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!