数据库面经(施工中...)


1 什么是数据库事务?

数据库事务(Database Transaction)是指作为单个逻辑工作单元执行的一系列操作,这些操作要么完全地执行,要么完全地不执行。它是一个不可分割的工作单位,事务中包括的操作要么全部做完,要么全部不做,不可能结束在中间某个环节。

事务通常由事务开始(BEGIN TRANSACTION)和事务结束(如COMMIT或ROLLBACK)之间执行的全部数据库操作组成。例如,在网上购物的一次交易中,付款过程就至少包括更新商品库存信息、保存客户付款信息、生成订单并保存到数据库中和更新用户相关信息等步骤,这些步骤就可以被看作是一个事务。

事务的目的是为了确保数据库始终保持一致状态,尤其是在多个用户同时访问和修改数据库时。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。事务必须满足所谓的ACID属性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)

数据库事务是数据库管理系统(DBMS)中的一项重要功能,它确保了对数据库的修改是安全、可靠和一致的。在开发涉及数据库的应用程序时,理解和正确使用事务是非常重要的。


2 数据库事务的特性?

数据库事务具有四大特性,这些特性通常简称为ACID特性,包括原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)

  1. 原子性(Atomicity):事务是一个原子操作单元,其对数据库的修改要么全都执行,要么全都不执行。也就是说,事务中的所有操作要么都执行,要么都不执行,不会出现部分操作成功或失败的情况。
  2. 一致性(Consistency):事务执行前后,数据库的数据必须保持一致性。这意味着事务的执行不能破坏数据库中的完整性约束,如唯一性约束、外键约束等。事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。
  3. 隔离性(Isolation):事务的执行应该相互隔离,每个事务的操作应该与其他事务的操作相互独立,互不干扰。即使多个事务同时并发执行,每个事务也应该感觉不到其他事务的存在。
  4. 持久性(Durability):事务一旦提交(或者说已经成功执行),其对数据库的修改应该是永久性的,即使系统发生故障,数据也不会丢失。数据库系统需要提供恢复机制,以确保事务的持久性。

这些特性确保了数据库事务的可靠性、一致性和持久性,保证了数据的完整性和可靠性。在进行数据库设计和操作时,理解和遵循这些事务特性是非常重要的。


3 什么是脏读,幻读,不可重复读?

脏读、幻读和不可重复读是数据库事务中的三种读取问题。

  1. 脏读(Dirty Read):当一个事务正在对一条记录进行修改,而这个修改还没有提交到数据库中,这时,另外一个事务也访问这条记录并读取了这条“脏”数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏”的,即这个数据可能是不正确的。如果第一个事务回滚,那么第二个事务获取的数据就是无效的,这就是脏读。
  2. 幻读(Phantom Read):是指在一个事务内读取了几行数据,然后另一个并发事务插入了一些新行,当原事务再次读取同一范围的数据时,会出现额外的“幻影”行。简单来说,幻读就是指在同一个事务中,多次执行相同的查询,但由于其他事务插入了新的数据,导致结果集不一致的情况
  3. 不可重复读(Non-repeatable Read):是指在一个事务内,多次读取同一数据,在这个事务还没有结束时,另外一个事务也访问该同一数据并进行了修改(如修改、删除等),那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,第一个事务两次读取到的数据可能是不一样的。这种情况就被称为是不可重复读。

这三种读取问题都可能导致数据的不一致性和错误,因此在数据库设计和应用中需要采取相应的措施来避免这些问题。例如,通过设置合适的事务隔离级别,可以在一定程度上防止脏读、幻读和不可重复读的发生。


4 事务的隔离级别和四级封锁协议?

事务的隔离级别和封锁协议是数据库管理系统中用于控制并发访问时可能产生的数据不一致问题的两种机制。

事务的隔离级别

事务的隔离级别定义了事务在处理时对其他事务的可见性。ANSI SQL标准定义了四种事务隔离级别:

  1. READ UNCOMMITTED(读未提交)

    • 事务可以读取其他未提交事务的修改。
    • 这是最低的隔离级别,可能会导致“脏读”(读取到其他事务未提交的修改)。
  2. READ COMMITTED(读已提交)

    • 一个事务只能读取已经提交的事务所做的修改。
    • 可以避免“脏读”,但可能会遇到“不可重复读”(在事务执行过程中,多次读取同一数据可能得到不同的结果)和“幻读”(在事务执行过程中,一个查询的结果集可能会因为其他事务的插入操作而发生改变)。
  3. REPEATABLE READ(可重复读)

    • 在事务执行期间,对同一数据的多次读取将返回相同的结果。
    • 可以避免“脏读”和“不可重复读”,但在某些数据库系统中可能仍然会遇到“幻读”。
  4. SERIALIZABLE(串行化)

    • 这是最高的隔离级别。事务被处理为串行事务,即事务不会并发执行。
    • 可以避免所有类型的读和写问题,但会大大降低系统的并发性能。

四级封锁协议

封锁协议通常用于控制对数据项的并发访问。虽然通常讨论的是三级封锁协议,但我们可以扩展概念到四级:

  1. 一级封锁协议

    • 事务在修改数据之前必须先对其加排他锁(写锁),直到事务结束才释放。
    • 防止了丢失修改,保证事务是可恢复的。
  2. 二级封锁协议

    • 一级封锁协议加上事务在读取数据之前必须先对其加共享锁(读锁),读完后即可释放。
    • 除了防止丢失修改外,还防止了读“脏”数据。
  3. 三级封锁协议

    • 一级封锁协议加上事务在读取数据之前必须先对其加共享锁,且共享锁在整个事务期间保持。
    • 除了防止丢失修改和不读“脏”数据外,还防止了不可重复读。
  4. 四级封锁协议

    • 对三级封锁协议的增强,通常通过在整个事务期间对所读取或更改的数据所在的表加表锁来实现。
    • 其他事务不能读写该表中的任何数据,从而避免了所有类型的并发问题。
    • 但这种方法的并发性能通常很低。

需要注意的是,封锁协议和事务隔离级别并不是严格对应的。不同的数据库系统可能会以不同的方式实现这些级别和协议,因此在具体使用时需要参考特定数据库系统的文档。


5 什么是数据库索引?索引的优缺点?

数据库索引是一种数据结构,它可以帮助加快数据库查询的速度。具体来说,索引是对数据库表中一列或多列的值进行排序的一种结构,通过索引可以快速访问数据库表中的特定信息。索引的作用类似于图书的目录,可以帮助我们快速找到所需的数据,而不必遍历整个数据库表。

索引的优点主要包括:

  1. 提高查询速度:索引可以大大加快数据的检索速度,特别是在大型数据集中查询时,可以节省大量的时间。通过使用索引,查询可以更快地定位到所需的数据行,避免了全表扫描的开销。
  2. 减少数据的扫描量:使用索引可以减少需要扫描的数据量,因为索引已经对表中的数据进行了排序和分组。当执行查询时,只需要扫描与查询条件相关的索引部分,而不是整个表。
  3. 保证数据的唯一性:通过创建唯一性索引,可以确保数据库表中的每一行数据都具有唯一性。这有助于维护数据的完整性和准确性。
  4. 加速表之间的连接:索引还可以加速数据库表之间的连接操作,特别是在实现数据库的参照完整性方面特别有意义。通过使用索引,可以更快地找到相关联的数据行,提高连接操作的效率。
  5. 优化查询性能:索引可以在查询优化器中使用,通过选择合适的索引来执行查询计划,从而提高系统的性能。查询优化器可以根据索引的统计信息和查询条件来选择最优的查询路径。

然而,索引也存在一些缺点:

  1. 占用额外的存储空间:为了支持索引,数据库需要额外的存储空间来维护索引数据结构。这可能会增加存储成本和管理复杂性。
  2. 增加更新时间:每次插入、更新或删除数据时,需要更新索引,这会增加数据操作的时间。因为索引需要保持与表数据的一致性,所以任何对表数据的修改都需要相应地更新索引。
  3. 可能导致性能下降:如果索引被错误地设计或过多使用,查询性能可能会下降。过多的索引会增加查询优化器的选择难度,并可能导致查询需要在多个索引之间进行切换,从而降低性能。此外,不恰当的索引设计也可能导致索引失效或无法充分利用索引的优势。
  4. 高并发环境下的锁竞争:在高并发的环境下,由于索引的存在,数据的修改操作需要加锁,可能会导致锁竞争,影响并发性能。多个事务同时修改同一数据行时,需要通过锁来保证数据的一致性和隔离性,但这也可能导致锁等待和死锁等问题。

因此,在使用索引时需要根据具体的应用场景和需求进行权衡和选择。需要综合考虑查询性能、数据更新频率、存储空间以及并发性能等因素来设计和优化索引策略。


6 数据库中的binlog是什么

binlog,即二进制日志(Binary Log),是MySQL数据库中一种非常重要的日志文件。它以二进制的形式记录了数据库所有的写入性操作(如CREATE、ALTER TABLE、INSERT、UPDATE、DELETE等),但不包括查询(如SELECT、SHOW等)操作,因为这些操作对数据本身并没有修改。

binlog日志是由MySQL的Server层进行记录的,无论使用何种存储引擎,只要MySQL数据库开启了binlog功能,就都会产生binlog日志。这些日志信息被保存在磁盘上的binlog文件中,通过追加的方式进行写入。当binlog文件的大小达到给定的定值时,会自动生成新的文件来保存日志。

binlog日志有两个主要的使用场景:主从复制和数据恢复。在主从复制中,Master端的写入操作会记录在binlog中,然后binlog会被发送到各个Slave端,Slave端通过重放binlog来达到主从数据一致。在数据恢复中,可以使用mysqlbinlog工具来解析binlog文件,将其中的SQL语句提取出来并执行,从而恢复数据库的数据。

需要注意的是,虽然binlog记录了数据库的写入性操作,但它并不是物理日志,而是逻辑日志。物理日志记录的是数据页的变更,而逻辑日志记录的是SQL语句。因此,在恢复数据时,需要根据binlog中的SQL语句来重新执行,而不是直接恢复数据页。

另外,由于binlog记录了所有的写入性操作,因此它会占用一定的磁盘空间。为了控制binlog的大小和数量,可以通过设置max_binlog_size参数来限制每个binlog文件的大小,并设置expire_logs_days参数来控制binlog文件的保留天数。当binlog文件的大小达到给定值或超过保留天数时,会自动被删除或归档。


7 数据库中的redolog是什么?

redo log,也被称为重做日志,是数据库管理系统(如MySQL的InnoDB存储引擎)中的一种关键日志类型。它属于物理日志,记录了数据修改的具体位置(即数据页上的具体偏移量),而不是像binlog那样的逻辑日志,记录的是SQL语句的具体内容。

redo log的主要目的是确保事务的持久性(Durability),这是ACID事务特性中的一个。即使在系统崩溃或其他故障情况下,redo log也能保证已提交事务的修改不会丢失,因为系统可以根据redo log中的记录来重新执行(重做)这些修改操作,从而恢复数据的一致性。

redo log通常采用循环写的方式,即当日志达到预定的大小时,从头开始继续写。这种设计使得日志的写入操作非常快速,因为不需要频繁地进行磁盘寻址。同时,为了保证数据的可靠性,redo log通常会被写入到磁盘的多个位置(如不同的磁盘或磁盘的不同区域),以防止单点故障导致的数据丢失。

在MySQL的InnoDB存储引擎中,redo log是固定大小的,并且是以文件的形式存在于磁盘上。当事务发生时,相关的修改会首先被写入到redo log中,然后再异步地刷新到磁盘的数据文件中。这种先写日志后写数据的方式被称为Write-Ahead Logging(WAL),它可以提高系统的性能和可靠性。

需要注意的是,虽然redo log和binlog都是MySQL中用于数据恢复的日志类型,但它们的用途和记录的内容是不同的。redo log主要用于保证事务的持久性和数据的可靠性,而binlog则主要用于主从复制和数据的时间点恢复等场景。在实际应用中,通常会同时使用这两种日志类型来满足不同的需求。

redo log,也称作重做日志,是数据库管理系统(DBMS)中的一个关键组件,尤其在像InnoDB这样的存储引擎中非常重要。redo log的主要目的是确保事务的持久性,即在系统崩溃或其他故障发生后,已提交的事务的更改不会丢失。

以下是redo log的一些核心特点和作用:

  1. 持久性保证:redo log是物理日志,记录的是数据页上的具体修改,而不是SQL级别的逻辑操作。这意味着在系统崩溃后,恢复过程可以通过重放(redo)这些物理更改来重建数据的状态,而不需要知道原始的SQL操作是什么。

  2. 写前日志(WAL):大多数现代数据库系统采用写前日志(Write-Ahead Logging, WAL)机制,即在实际修改数据页之前,先确保相关的redo log条目已经被写入并持久化到磁盘上。这样,即使系统在数据页写入之前崩溃,也可以通过redo log来恢复数据。

  3. 循环写入:redo log通常被组织成一组固定大小的日志文件,以循环方式写入。当到达一个日志文件的末尾时,写入操作会切换到下一个日志文件。这种设计简化了日志的管理和清理过程。

  4. 崩溃恢复:在数据库系统启动时,如果需要,可以通过读取和分析redo log来进行崩溃恢复。系统会确定哪些事务已经提交但更改可能尚未完全写入数据文件,然后重放这些事务的redo log条目来确保数据的一致性。

  5. 性能优化:由于redo log的写入是顺序的,并且通常被缓存和批量写入磁盘,因此它通常比随机写入数据页要快得多。这种设计有助于减少I/O延迟,提高数据库系统的吞吐量。

  6. 事务协调:redo log还用于协调多个并发事务的更改,确保它们在系统崩溃后能够以正确的顺序恢复。

在MySQL的InnoDB存储引擎中,redo log通常被实现为两个或更多的预配置大小的日志文件(如ib_logfile0ib_logfile1等),这些文件在MySQL服务器运行时被循环使用。这些日志文件的配置和大小可以根据应用程序的需求进行调整,以平衡持久性保证和磁盘空间使用。


8 为什么MySQL索引要使用B+树,而不是B树或者红黑树?

MySQL选择B+树作为索引结构的原因涉及多个方面的考虑,主要包括磁盘I/O操作、查询效率、数据维护等方面。以下是对为什么选择B+树而不是B树或红黑树的详细解释:

1. 磁盘I/O操作

数据库索引是存储在磁盘上的,因此磁盘I/O操作的效率是选择索引结构时需要考虑的重要因素。与内存相比,磁盘I/O操作非常耗时。B+树和B树都是平衡的多路搜索树,它们的设计目标之一就是减少磁盘I/O操作次数。

  • B+树与B树:B+树和B树都能将多个键值对存储在一个节点中,从而最大限度地利用磁盘块(或称为页)的存储空间。这减少了查找过程中需要访问的磁盘块数量。
  • B+树的优势:与B树相比,B+树的所有值都位于叶子节点,并且叶子节点之间通过指针链接。这使得B+树在范围查询时更加高效,因为一旦找到范围的起始点,就可以通过叶子节点之间的指针顺序访问后续节点,而无需回到上层节点。

2. 查询效率

  • B+树的叶子节点:由于B+树的所有键值对都存储在叶子节点,并且叶子节点处于同一层,因此查询效率相对稳定。这意味着无论查询哪个键,都需要进行相同数量的磁盘I/O操作。
  • 红黑树:红黑树是一种自平衡的二叉搜索树,它在内存中表现良好。然而,在磁盘I/O方面,红黑树不如B+树高效。因为红黑树的每个节点只存储一个键值对,所以在查找过程中可能需要访问更多的磁盘块。

3. 数据维护

  • B+树的平衡性:B+树是一种平衡树,这意味着在插入和删除操作时,树的深度不会发生显著变化。这保证了查询性能的稳定。
  • 红黑树的维护:虽然红黑树也是自平衡的,但由于其每个节点只存储一个键值对,因此在维护平衡时可能需要进行更多的旋转和颜色调整操作。这些操作在磁盘I/O方面可能不如B+树高效。

总结

综上所述,MySQL选择B+树作为索引结构的主要原因是它在磁盘I/O操作、查询效率和数据维护方面都具有优势。与B树相比,B+树在范围查询方面更加高效;与红黑树相比,B+树在磁盘I/O操作和查询效率方面表现更优。这些特点使得B+树成为数据库索引的理想选择。


9 MySQL中有哪些索引?有什么特点?

MySQL支持多种类型的索引,每种索引都有其特定的使用场景和优势。以下是MySQL中常见的索引类型及其特点:

  1. B+树索引

    • 主键索引(Primary Key):唯一标识表中每条记录的一个或一组字段,确保数据的唯一性。主键索引也是聚簇索引,数据按照主键的顺序存储。
    • 唯一索引(Unique Key):与主键类似,唯一索引也要求索引列的值必须唯一,但允许有空值。一个表可以有多个唯一索引。
    • 普通索引(Index 或 Key):最基本的索引,没有任何限制。它主要用于提高数据检索的速度,但对表中的记录没有唯一性的要求。

    B+树索引的特点:

    • 所有的索引都存储了相应的行数据指针(对于非聚簇索引,存储的是主键值),可以快速定位到具体的数据行。
    • 索引树是平衡的,保证了查询性能的稳定。
    • 叶子节点之间通过指针相连,便于范围查询。
  2. 全文索引(Full-Text)

    • 主要用于在文本数据中进行快速的全文搜索。它支持自然语言查询、布尔查询和查询扩展等模式。
    • 全文索引目前仅支持MyISAM和InnoDB存储引擎(从MySQL 5.6版本开始,InnoDB也支持全文索引)。
  3. 空间索引(Spatial)

    • 用于地理空间数据类型(如点、线和多边形等)的索引。
    • 空间索引基于R-tree数据结构,支持空间数据的高效查询。
    • MySQL中的空间索引目前主要用于MyISAM存储引擎,但从MySQL 5.7开始,InnoDB也开始支持空间索引。
  4. 哈希索引(Hash Index)

    • 精确查找非常快,因为哈希索引在精确查找时几乎可以一次定位到数据。
    • 但是,哈希索引对于范围查询、排序等操作则无能为力,因为哈希函数只能保证单个键值的快速定位。
    • 在MySQL中,MEMORY存储引擎支持哈希索引。
  5. 前缀索引(Prefix Index)

    • 如果一个字段很长,建立完整的索引会消耗大量的存储空间并降低查询效率。此时,可以考虑为该字段的前N个字符建立索引,即前缀索引。
    • 前缀索引可以大大减小索引的大小,从而提高查询速度。但需要注意的是,前缀索引只适用于精确匹配查询,不适用于范围查询和排序等操作。
  6. 复合索引(Composite Index)

    • 复合索引是基于多个列的索引。它允许用户根据多个列的值进行查询和排序操作。
    • 复合索引遵循最左前缀原则,即查询条件中必须包含索引的最左列才能充分利用索引。如果查询条件中只包含了复合索引的部分列,那么索引的利用效果会大打折扣。

了解不同索引的特点和使用场景有助于在设计数据库时选择合适的索引类型,从而提高查询性能和系统的整体效率。


10 常见的数据库引擎

常见的数据库引擎包括以下几种:

  1. InnoDB:InnoDB是MySQL的默认存储引擎,它提供了事务安全(ACID兼容)和具有提交、回滚和崩溃恢复能力的事务。InnoDB通过多版本并发控制(MVCC)来支持高并发性,并且具有行级锁定和外键约束。
  2. MyISAM:(mai-ai-sam)MyISAM是MySQL以前的默认存储引擎,它提供了全文索引、压缩、空间函数等特性。但是,MyISAM不支持事务和行级锁定,因此在需要高并发写入的场景下性能可能不佳。
  3. MongoDB:MongoDB是一种面向文档的NoSQL数据库引擎,它使用BSON(一种类似于JSON的二进制格式)来存储数据。MongoDB支持动态模式,具有水平扩展能力,并且提供了丰富的查询语言和索引功能。
  4. PostgreSQL:PostgreSQL是一种开源的关系型数据库引擎,它支持SQL标准并且提供了许多高级功能,如复杂查询、外键、视图、事务等。PostgreSQL还支持多种扩展和自定义功能,可以满足各种应用的需求。
  5. Microsoft SQL Server:SQL Server是微软开发的一种关系型数据库引擎,它提供了全面的SQL支持、事务处理、复制和分布式查询等功能。SQL Server还支持多种数据类型和存储过程,并且可以与Windows操作系统紧密集成。
  6. Oracle Database:Oracle Database是甲骨文公司开发的一种商业关系型数据库引擎,它提供了高性能、可靠性和安全性。Oracle支持多种数据类型和查询语言,并且具有强大的事务处理和复制功能。
  7. SQLite:SQLite是一种轻量级的关系型数据库引擎,它不需要独立的服务器进程,可以直接嵌入到应用程序中。SQLite引擎适用于小型应用程序、移动设备以及需要快速原型设计的情况。
  8. Redis:Redis是一种开源的内存数据库管理系统,被广泛用于缓存和消息队列等应用场景。
  9. NoSQL:全称为"Not Only SQL",是一项全新的数据库革命性运动。它指的是非关系型的数据库,与传统的关系型数据库相比,NoSQL数据库具有非关系型的、分布式的、开源的、水平可扩展的特性。

这些数据库引擎各有优缺点,适用于不同的应用场景和需求。在选择数据库引擎时,需要考虑数据模型、并发性、事务处理、扩展性、安全性以及与其他系统的集成等因素。


11 说下你了解的MVCC机制?包括其中的原理?

MVCC(多版本并发控制,Multi-Version Concurrency Control)是一种在数据库管理系统中实现事务并发控制的技术。它的主要目的是提高数据库的并发性能,使得多个事务可以同时访问同一份数据,而不会相互阻塞。

MVCC机制的基本原理是:对于每个事务,数据库系统都会为其分配一个唯一的事务ID,并且每个数据项都会维护多个版本,每个版本都会对应一个事务ID。当一个事务读取数据时,它只能看到那些在其开始之前就已经提交的事务所做的修改,也就是只能读取到比它早的事务ID对应的数据版本。这样,即使有多个事务同时对同一份数据进行读写操作,它们也不会相互干扰,因为每个事务看到的数据版本都是不同的。

在MVCC中,读操作是非阻塞的,因为读操作不需要等待其他事务的完成,它只需要读取对应版本的数据即可。而写操作(修改数据)则需要先复制一份当前数据版本,然后在此基础上进行修改,形成一个新的数据版本。这个新版本的数据在事务提交之前对其他事务是不可见的,只有当事务提交后,其他事务才能看到新的数据版本。

为了实现MVCC,数据库系统需要维护一个版本链,也就是每个数据项的多个版本按照事务ID的顺序链接在一起。同时,数据库系统还需要记录每个事务的读视图(read view),即该事务在开始时能够看到的数据版本范围。通过比较数据版本的事务ID和事务的读视图,数据库系统可以确定一个事务是否能够看到某个数据版本。

总的来说,MVCC机制通过为每个事务分配唯一的事务ID,并维护多个数据版本来实现并发控制。它使得多个事务可以同时访问同一份数据而不会相互干扰,从而提高了数据库的并发性能。同时,由于读操作是非阻塞的,因此也可以提高数据库的读取性能。

但是需要注意的是,MVCC只适用于读已提交(RC)和可重复读(RR)这两种事务隔离级别。在串行化(Serializable)隔离级别下,由于需要保证事务的串行执行顺序,因此不能使用MVCC机制来避免读写冲突。此外,MVCC机制的实现也需要消耗一定的存储空间和维护成本,因为需要为每个数据项维护多个版本。因此,在实际应用中需要根据具体的场景和需求来选择合适的并发控制机制。

posted @   guanyubo  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示