【面试题】mysql常见面试题及答案总结

事务中的ACID原则是什么? Mysql是如何实现或者保障ACID的?

ACID原则是数据库事务管理中必须满足的四个基本属性,确保了数据库事务的可靠性和数据完整性。

简写 全称 解释 实现
A 原子性(Atomicity) 一个事务被视为一个不可分割的操作序列,这些操作要么全部成功完成,要么全部不执行。如果事务中的任何部分失败,则整个事务将被回滚到事务开始前的状态。 在MySQL中,通过使用InnoDB存储引擎实现原子性。InnoDB使用redo log(重做日志)来保证即使在系统崩溃的情况下,也能通过重做已经记录的日志而恢复未提交事务的更改;同时使用undo log(回滚日志)来撤销已执行但未提交的事务对数据库所做的修改。
C 一致性(Consistency) 事务完成后,数据库从一个一致状态变换到另一个一致状态,即无论事务是否执行,系统的业务规则始终得到维护。 在MySQL中,通过使用InnoDB存储引擎实现原子性。InnoDB使用redo log(重做日志)来保证即使在系统崩溃的情况下,也能通过重做已经记录的日志而恢复未提交事务的更改;同时使用undo log(回滚日志)来撤销已执行但未提交的事务对数据库所做的修改。
I 隔离性(Isolation) 多个事务并发执行时,每个事务都好像在单独执行一样,不会受到其他事务的影响。 MySQL提供了多种事务隔离级别(读未提交、读已提交、可重复读和串行化),通过不同级别的锁定机制控制事务间的可见性和并发副作用。默认情况下,InnoDB使用的是可重复读隔离级别。
D 持久性(Durability) 一旦事务提交成功,它对数据库的修改就被永久保存下来,即使发生系统故障也不会丢失。 InnoDB同样利用redo log实现持久性。当事务提交时,其改动先写入redo log buffer,然后通过innodb_flush_log_at_trx_commit参数配置的不同策略将其刷入磁盘上的redo log文件,从而确保即使在服务器宕机后,也能够通过redo log进行恢复,使得已提交的事务具有持久性。

综上所述,MySQL通过InnoDB存储引擎提供的redo log、undo log、行级锁定以及其他一系列机制,实现了ACID事务管理的要求。


介绍下innodb的聚簇索引

聚簇索引(Clustered Index)是数据库中表数据的一种物理存储方式,尤其是在关系型数据库管理系统如MySQL的InnoDB存储引擎中得到广泛应用。

实现

聚簇索引的数据结构通常采用B+树(B-plus Tree)。

在MySQL的InnoDB存储引擎中,聚簇索引的具体实现如下:

  • B+树结构:聚簇索引是基于B+树建立的。B+树是一种自平衡的多路搜索树,每个节点可以有多个子节点,并且所有的叶子节点都在同一个层级上,形成了一个有序链表。
  • 叶子节点存储数据:在聚簇索引中,B+树的叶子节点不仅包含索引键值,还包含了完整的行数据。这意味着数据行就是按照索引键值排序并物理存储在磁盘上的。
  • 主键作为聚簇索引:对于InnoDB存储引擎,默认情况下,如果表定义了主键,那么主键列就会被用作聚簇索引的键。如果没有显式定义主键,则会选择一个唯一的非空索引(如果存在),否则会生成一个内部row_id作为聚簇索引的键。
  • 二级索引引用聚簇索引:当创建非聚簇索引(二级索引)时,其叶子节点不再直接包含行数据,而是存储对应行的主键值。查询时,先通过二级索引找到主键值,再通过聚簇索引定位到实际的数据行。
    这种设计使得对主键进行范围扫描或顺序访问时效率很高,同时也优化了二级索引的性能,因为它们可以通过链接快速定位到相应的行数据。

优势

  • 数据访问更快:由于索引和数据位于同一B+树中,根据主键查询时可以直接定位到数据,无需额外回表操作,因此性能非常高。
  • 数据局部性:聚集索引使得相关数据紧密地存储在一起,对于范围查询非常高效,因为连续的索引键通常对应着物理位置相邻的数据页,这有助于减少磁盘I/O次数。
  • 辅助索引优化:即使是对非主键的二级索引(非聚簇索引),其叶子节点存储的是对应的主键值,而非行的所有信息。当通过二级索引查找数据时,需要两次索引查找,但第二次查找是在聚簇索引中,可以利用到聚簇索引的优点。
  • 插入效率:如果数据按照主键的自然顺序插入,并且主键值增长较为连续,那么插入操作相对高效,因为新记录往往会被添加到现有数据文件的末尾,而不会引起大量的页分裂或重组。

劣势:

  • 按照主键递增顺序进行,可能导致页分裂,影响性能。
  • 更新主键代价较高,尤其是当主键更新导致行需要移动到新的位置时。
  • 删除操作可能导致页内空间碎片,需要维护以保持页面填充率。

Innodb引擎是如何实现多版本控制的

MySQL中的版本控制通常是指多版本并发控制(MVCC,Multi-Version Concurrency Control),特别是在InnoDB存储引擎中实现的这一特性。MVCC主要用于管理并发事务间的读写冲突,并在某种程度上提供了数据的历史版本查看能力,以支持事务的隔离性和一致性。

多版本并发控制(MVCC)工作原理:

  • 在InnoDB中,每个事务都有自己的视图(read view),即它能看到的数据版本范围。
  • 每行记录除了包含当前值之外,还包含隐藏的系统列(如DB_TRX_ID、DB_ROLL_PTR和DB_ROW_ID等),用于追踪该行记录的创建事务ID、回滚指针和其他信息。
  • 读操作根据不同的事务隔离级别,可以读取不同版本的数据:
    • 在可重复读(Repeatable Read)隔离级别下,一个事务开启后看到的同一行记录在整个事务期间始终不变,即使其他事务已经修改并提交了这条记录。
    • 在读已提交(Read Committed)隔离级别下,每次查询都会获取最新的已提交版本。
  • 写操作会生成新的行版本,旧版本在一定条件下会被垃圾回收机制清理。

通过这种机制,多个事务可以在同一时刻看到数据库的不同版本状态,从而避免了大量的锁定冲突,提高了系统的并发性能。虽然这并不是严格意义上的"版本控制系统"(如Git或SVN等用于代码版本控制的工具),但在数据库领域内,MVCC为了解决并发控制问题提供了一种非常有效的"版本化"处理方式。同时,结合SQL语句的ROLLBACK功能,用户也可以在事务层面实现对自身操作的撤销,达到回滚效果。


MySql中的事务隔离级别

MySQL中的事务隔离级别定义了在并发事务执行时,对数据的访问和修改如何进行隔离,以防止不同事务之间的相互影响导致的数据不一致。根据ANSI SQL标准,MySQL支持以下四种事务隔离级别:

  • 读未提交(Read Uncommitted):

    这是最低级别的隔离,一个事务可以读取到其他事务尚未提交的数据更改。这种情况下可能出现"脏读"现象,即事务读到了随后可能被回滚的数据。

  • 读已提交(Read Committed):

    在这个级别,一个事务只能看到其他事务已经提交的数据。这意味着在一个事务开始后,即使有其他事务对其之前读取过的数据进行了修改并提交,当事务也不会再看到这些修改前的数据,从而避免了"脏读"。但仍然存在"不可重复读"问题,即在同一事务中多次读取同一行数据可能会得到不同的结果,为其他事务可能在此期间提交了对该行数据的更新。

  • 可重复读(Repeatable Read):

    这是MySQL的默认事务隔离级别。在该级别下,一个事务在整个生命周期内所读取的数据都是事务开始时的状态,即不会看到其他事务在其执行过程中提交的更新,因此避免了"脏读"和"不可重复读"。然而,在此级别下,由于幻读(Phantom Reads)的问题依然存在,即同一个事务在两次查询之间可能会看到一些新插入的满足查询条件的记录。

  • 串行化(Serializable):

    这是最高的隔离级别,提供了完全的事务隔离。为了实现这一点,数据库通常会使用悲观锁或其他机制来确保事务间的操作按序列执行,从而避免所有并发问题,包括"脏读"、"不可重复读"以及"幻读"。但是,这也可能导致大量的锁定和更高的并发冲突,从而降低系统的整体性能。

每种隔离级别都有其适用场景和相应的权衡,选择合适的事务隔离级别需要根据具体的应用需求和对数据一致性的要求来决定。


大数据量表的查询如何优化

优化方向 具体描述
索引优化 创建合适的索引:对经常用于查询条件的列创建索引,尤其是那些出现在JOIN、WHERE、ORDER BY和GROUP BY子句中的列。但要注意,对于大数据量表,如果全表扫描速度仍然较快,或者索引维护成本过高(如插入、更新时频繁重建索引),则可能不适用。 选择正确的索引类型:B-Tree索引适合于范围查询和精确匹配;哈希索引适合于等值查询;全文索引用于全文本搜索。 索引覆盖查询:确保查询只通过索引就能获取所有需要的数据,避免回表操作。
SQL语句优化 避免全表扫描:尽量减少使用SELECT * FROM table,而是明确指定所需的列。 减少JOIN操作:不必要的JOIN会导致查询性能下降,尤其是在关联大表时。可以通过预处理或提前汇总数据来简化查询结构。 使用更有效的JOIN顺序:根据表的实际大小和索引情况调整JOIN顺序,优先JOIN小表或已建立有效索引的表。 利用连接条件筛选数据:在JOIN之前先对表进行过滤,减少JOIN后数据集的大小。 避免在WHERE子句中使用函数或复杂的表达式,这可能会导致无法利用索引。
分区与分片 表分区(Partitioning):将一个大表物理上划分为多个较小的部分,可以基于时间、范围或其他逻辑字段进行划分。这样可以提高查询效率,特别是当查询条件能限制到单个或少量分区时。 数据分片(Sharding):按照某种规则将数据分布到不同的数据库服务器或实例上,以分散存储和访问压力,提高系统的可扩展性。
临时表与中间结果集 使用临时表或表变量暂存中间结果,尤其在执行多步复杂查询时,可以减少计算量和I/O次数。 对于大量数据的统计计算,可以考虑定期生成汇总表,避免实时统计大规模原始数据。
硬件与配置调优 增加内存容量,提高缓存命中率,减少磁盘I/O。 调整数据库系统参数,比如增大缓冲池大小、合理设置排序区大小、调整事务日志相关参数等。
并发控制与锁管理 控制并发查询的数量,适当增加并行度,但要防止过多的锁竞争导致性能瓶颈。 尽量采用低级别的锁定机制(如行级锁或页级锁),避免使用表级锁造成不必要的阻塞
使用特定数据库引擎特性 如MySQL InnoDB存储引擎支持MVCC(多版本并发控制)提高读写并发性能,可以根据业务场景调整事务隔离级别。 对于分布式数据库系统,充分利用其内置的分布式查询优化机制。
监控与分析 定期分析查询计划,找出潜在的性能瓶颈,并针对性地进行优化。 监控系统资源使用情况,包括CPU、内存、I/O以及网络带宽等,根据实际情况进行相应调整

以上这些策略并不是孤立使用的,通常需要综合考虑应用的具体需求和数据库的运行状况,灵活采取相应的优化措施。


在MySQL中,如何设计高可用性的数据库架构以保证数据安全和业务连续性?

可以采用如下策略:

  • 主从复制(Replication):构建一主多从结构,主库负责写操作,从库实时同步主库数据并提供读服务。
  • 集群解决方案:如MySQL Group Replication或MySQL InnoDB Cluster,实现多节点间的数据同步和故障切换。
  • 数据分片与分布式数据库系统:将数据分散到多个服务器上,降低单点压力,提高性能和可用性。
  • 使用高可用中间件如ProxySQL进行读写分离和负载均衡。
  • 定期备份并结合Binlog恢复机制,确保数据灾难恢复能力。

MySQL中有哪些常见的死锁情况?怎样避免和解决死锁?

常见死锁情况包括两个事务相互等待对方持有的锁资源导致循环等待。例如,事务A锁定表A并请求锁定表B,同时事务B已经锁定表B并请求锁定表A。

避免和解决死锁的方法:

  • 设定合理的事务大小和执行顺序,尽量减少持有锁的时间。
  • 使用较低的事务隔离级别,如从"可重复读"降低到"读已提交",尽管这可能导致更多的不可重复读问题。
  • 设置锁超时,当等待锁超过一定时间自动回滚事务。
  • MySQL自身有检测死锁的机制,一旦检测到死锁会主动回滚其中一个事务以打破死锁循环。

相关推荐
Rookie也要加油27 分钟前
01_SQLite
数据库·sqlite
liuxin3344556632 分钟前
教育技术革新:SpringBoot在线教育系统开发
数据库·spring boot·后端
看山还是山,看水还是。1 小时前
MySQL 管理
数据库·笔记·mysql·adb
fishmemory7sec1 小时前
Koa2项目实战2(路由管理、项目结构优化)
数据库·mongodb·koa
momo小菜pa2 小时前
【MySQL 09】表的内外连接
数据库·mysql
Jasonakeke2 小时前
【重学 MySQL】四十九、阿里 MySQL 命名规范及 MySQL8 DDL 的原子化
数据库·mysql
程序猿小D2 小时前
第二百六十九节 JPA教程 - JPA查询OrderBy两个属性示例
java·开发语言·数据库·windows·jpa
小宇成长录2 小时前
Mysql:数据库和表增删查改基本语句
数据库·mysql·数据库备份
团儿.3 小时前
解锁MySQL高可用新境界:深入探索MHA架构的无限魅力与实战部署
数据库·mysql·架构·mysql之mha架构
程序猿小D3 小时前
第二百六十七节 JPA教程 - JPA查询AND条件示例
java·开发语言·前端·数据库·windows·python·jpa