2023-12-12
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.skjava.com/mianshi/tiji/1496303423

数据库基础知识

数据库的三范式是什么?

  1. 第一范式(1NF):表中的每个列都必须包含原子值,这意味着每个列中的数据不能再分解为更小的数据单元。这可以确保每个数据单元都是不可再分的。
  2. 第二范式(2NF):在满足第一范式的基础上,还要确保表中的非主键列都完全依赖于表的候选键(即,没有部分依赖)。这意味着非主键列不能依赖于候选键的一部分,它们必须与整个候选键相关。
  3. 第三范式(3NF):在满足第二范式的基础上,还要确保表中的非主键列之间没有传递依赖关系。这意味着非主键列不能相互依赖,而应该直接依赖于主键或其他候选键。

遵循三范式有助于减少数据冗余,提高数据的一致性和完整性,使数据库更容易维护和更新。然而,有时根据具体的应用需求,可能需要违反一些范式来优化性能或满足特殊要求。因此,在数据库设计中,需要权衡范式的遵守和应用的实际需求。

事务的基本要素 ACID

原子性(Atomicity):原子性确保事务是不可分割的单元,要么全部执行成功,要么全部失败。如果事务的任何部分失败,整个事务都会被回滚到初始状态,以确保数据库不会处于部分完成的状态。

一致性(Consistency):一致性要求事务在执行前后必须保持数据库的一致性。这意味着事务应该将数据库从一个一致的状态转换到另一个一致的状态,不会破坏数据库的完整性约束。如果事务违反了一致性规则,它将被回滚。

隔离性(Isolation):隔离性确保同时执行多个事务时,每个事务都是相互隔离的,不会相互干扰。这意味着一个事务的操作对其他事务是不可见的,直到该事务提交。这可以防止并发执行事务时发生不一致的情况。

持久性(Durability):持久性确保一旦事务提交,其结果将被永久保存在数据库中,即使系统崩溃或重新启动也不会丢失。这通常通过将事务的更改记录到持久存储(例如磁盘)来实现。

drop、delete 与 truncate 区别?

drop

  • 功能:DROP 用于删除整个数据库对象,可以是表、视图、索引、存储过程等。
  • 影响:DROP 删除的对象以及对象中包含的所有数据都会被永久删除,无法恢复。这是一个非常危险的操作,需要谨慎使用。

delete

  • 功能:DELETE 用于删除表中的数据行,可以根据特定的条件选择要删除的数据。
  • 影响:DELETE 只删除符合条件的数据行,而不删除表本身。删除的数据可以使用事务日志进行恢复,但通常需要较大的系统开销。

truncate

  • 功能:TRUNCATE 用于删除表中的所有数据,但保留表的结构以及有关表的信息(例如,列的定义、索引等)。

  • 影响:TRUNCATE 操作通常比 DELETE 更快,因为它不会逐行删除数据,而是直接截断表的数据。删除的数据无法使用事务日志进行恢复,但 TRUNCATE 操作通常会释放存储空间并重置表的自增计数器(如果有的话)。

  • 使用 DROP 来删除整个数据库对象,包括数据和定义。

  • 使用 DELETE 来删除特定条件下的数据行,但保留表的定义。

  • 使用 TRUNCATE 来删除表中的所有数据,但保留表的定义。 TRUNCATE 通常比 DELETE 更快,但不能用于删除部分数据或满足特定条件的数据。根据需要选择合适的操作。

什么是内联接、左外联接、右外联接?

内联接(Inner Join)

  • 内联接是最常用的连接类型,它返回两个表中符合连接条件的行。
  • 只返回两个表中匹配的行,不包括任何表中没有匹配的行。
  • 如果一个表中的某行在另一个表中没有匹配的行,那么这些行将被忽略。
  • 语法示例:SELECT * FROM table1 INNER JOIN table2 ON table1.column = table2.column;

左外联接(Left Outer Join)

  • 左外联接返回左表中的所有行,以及右表中与左表匹配的行。
  • 如果右表中没有与左表匹配的行,返回的结果集中将包括右表的列,但数据将为空。
  • 语法示例:SELECT * FROM table1 LEFT JOIN table2 ON table1.column = table2.column;

右外联接(Right Outer Join)

  • 右外联接与左外联接相反,它返回右表中的所有行,以及左表中与右表匹配的行。
  • 如果左表中没有与右表匹配的行,返回的结果集中将包括左表的列,但数据将为空。
  • 语法示例:SELECT * FROM table1 RIGHT JOIN table2 ON table1.column = table2.column;

说说在 MySQL 中一条查询 SQL 是如何执行的?

在 MySQL 中,一条查询 SQL 语句是如何执行的可以简要概括为以下步骤:

  1. SQL 解析和语法分析
    • MySQL 首先对接收到的 SQL 语句进行解析和语法分析,以确定查询的结构和语法是否正确。
  2. 查询优化
    • 一旦语法验证通过,MySQL 使用查询优化器来生成查询计划。查询优化器的目标是找到最有效的执行路径,以最小化查询的成本。它会考虑索引、连接顺序、过滤条件等因素来生成最佳的执行计划。
  3. 权限检查
    • MySQL 在执行查询之前会检查用户对数据的权限,确保用户有权执行该查询。
  4. 查询执行
    • 一旦生成了优化的查询计划并进行了权限检查,MySQL 开始执行查询。查询执行的具体步骤如下:
      • 从磁盘读取数据:如果数据不在内存中,MySQL 将从磁盘读取数据并将其加载到内存中。
      • 执行查询计划:MySQL 按照查询计划中的步骤执行查询,包括表扫描、索引查找、排序、连接等操作。
      • 返回结果:查询执行后,MySQL 将结果返回给用户或应用程序。
  5. 事务管理
    • 如果查询包含在事务中,MySQL 将负责管理事务的开始、提交和回滚,以确保事务的原子性、一致性、隔离性和持久性(ACID 属性)。
  6. 缓存和优化
    • MySQL 使用查询缓存来存储频繁查询的结果,以提高性能。如果启用了查询缓存,并且查询的结果已经缓存,MySQL 可能会直接返回缓存的结果而不执行查询。
  7. 日志记录
    • MySQL 记录查询和事务的日志,以便在需要时进行回滚或恢复数据。
  8. 数据更新(如果适用):
    • 如果查询包含数据更新操作(如INSERT、UPDATE、DELETE),MySQL 将相应地更新数据库中的数据,并确保操作的原子性。
  9. 资源释放
    • 最后,MySQL 释放查询期间使用的资源,包括锁定的表、内存和其他系统资源。

存储引擎

MyISAM 和 InnoDB 有什么区别?

事务支持

  • MyISAM:不支持事务。MyISAM 存储引擎不具备事务管理功能,因此不能用于需要 ACID(原子性、一致性、隔离性和持久性)事务支持的应用。
  • InnoDB:支持事务。InnoDB 存储引擎支持事务,因此适用于需要强大事务支持的应用,如银行、电子商务等。

行级锁和表级锁

  • MyISAM:使用表级锁。当对 MyISAM 表进行读写操作时,会锁定整个表,这可能导致并发性能问题。
  • InnoDB:使用行级锁。InnoDB 存储引擎支持更细粒度的锁定,允许多个事务并发地操作同一张表的不同行,从而提高了并发性能。

外键约束

  • MyISAM:不支持外键约束。MyISAM 不支持定义外键关系,因此不能强制执行参照完整性。
  • InnoDB:支持外键约束。InnoDB 支持定义外键关系,可以强制执行参照完整性,确保数据一致性。

崩溃恢复

  • MyISAM:不支持崩溃恢复。如果数据库发生崩溃或停电,MyISAM 表可能会损坏,需要手动修复。
  • InnoDB:支持崩溃恢复。InnoDB 存储引擎具有崩溃恢复机制,可以在数据库发生崩溃时恢复数据的一致性。

全文搜索

  • MyISAM:支持全文搜索。MyISAM 存储引擎提供了全文搜索功能,适用于需要执行全文搜索的应用。
  • InnoDB:不支持内置全文搜索。InnoDB 不支持与 MyISAM 相同的全文搜索功能,但可以通过其他插件或外部工具来实现全文搜索。

空间数据类型

  • MyISAM:不支持空间数据类型。MyISAM 不支持地理信息(GIS)和空间数据类型。
  • InnoDB:支持空间数据类型。InnoDB 支持地理信息(GIS)和空间数据类型,适用于地理信息系统和位置相关的应用。

为什么 SELECT COUNT(*) FROM table 在 InnoDB 比 MyISAM 慢?

对于 SELECT COUNT(*) FROM table 语句,在没有 WHERE 条件的情况下,InnoDB 比 MyISAM 可能会慢很多,尤其在大表的情况下。因为:

  • MyISAM 存储引擎在表中维护一个计数值,用于存储表中的总行数。因此,对于 SELECT COUNT(*) 查询,MyISAM 可以直接返回这个计数值,速度较快。
  • InnoDB 存储引擎没有类似的计数值,因此在执行 SELECT COUNT(*) 查询时,它需要扫描整个表来计算行数,这可能会比较耗时,特别是对于大型表。

数据类型

MySQL 中 varchar 与 char 的区别?

在 MySQL 中,VARCHAR 和 CHAR 是两种用于存储文本数据的字符数据类型,它们之间有以下主要区别:

  1. 存储方式
    • CHAR 字符串会被空格填充到固定长度,不足的部分会用空格字符填充。例如,如果定义一个长度为 10 的 CHAR 列,并插入 "ABC",它将存储为 "ABC "(总长度为 10)。
    • VARCHAR 字符串只会存储实际字符,不会填充空格。例如,如果定义一个长度为 10 的 VARCHAR 列,并插入 "ABC",它将存储为 "ABC"(总长度为 3)。
  2. 存储空间
    • CHAR 存储固定长度的字符串,因此它会占用固定数量的存储空间,无论实际字符串的长度。这可能会导致存储浪费,尤其是对于较短的字符串。
    • VARCHAR 存储实际字符的长度,因此它会根据实际数据的长度来占用存储空间,通常比 CHAR 更节省空间。
  3. 性能
    • 由于 CHAR 列的数据总是固定长度,因此在某些情况下,CHAR 可能会更快,因为它不需要在存储和检索时计算字符串的长度。但在大多数情况下,性能差异很小,可以忽略不计。
  4. 索引
    • CHAR 和 VARCHAR 列都可以被索引,但由于存储方式不同,它们的索引可能会有所不同。CHAR 列的索引可能会更大,因为它存储了填充的空格字符。
  5. 适用场景
    • 通常情况下,如果您知道数据的长度是固定的,例如身份证号码或电话号码,可以使用 CHAR 来存储,以确保固定长度和更好的性能。对于可变长度的文本,如用户名、地址等,通常使用 VARCHAR 更合适,因为它更节省存储空间。

varchar(1) 中的 10 代表的涵义?

10 表示该列的最大字符长度是 30 个字符。这意味着您可以在这个列中存储最多 30 个字符的文本数据,但也可以存储更短的文本,因为 VARCHAR 类型的列可以根据存储的实际文本长度动态调整存储空间。

int(11) 中的 11 代表什么涵义?

在 MySQL 中,int(11) 中的 11 并不代表整数的存储长度,而是用于显示的宽度(或者称为补零宽度)。

int 数据类型在 MySQL 中有固定的存储大小,不受宽度参数的影响。对于 int 类型,它总是占据 4 个字节(32 比特)的存储空间,范围是从 -2,147,483,6482,147,483,647

因此,int(11)int(5) 存储的整数范围和存储大小是相同的,但在显示值时,int(11) 可能会在左侧填充零,以保持总共显示 11 个字符的宽度。这对于一些应用中的排列和格式化输出可能有用,但不会影响整数的实际存储。

BLOB 和 TEXT 有什么区别?

数据类型

  • BLOB 是用于存储二进制数据的数据类型,例如图像、音频、视频等。
  • TEXT 是用于存储文本数据的数据类型,通常用于存储大段文本,如文章、评论、日志等。

字符集

  • BLOB 是二进制数据,没有字符集的概念,因此不会对数据进行字符集转换。
  • TEXT 存储文本数据,并且可以指定字符集,以确保正确的字符编码和排序。

存储方式

  • BLOB 存储二进制数据的字节序列,不对数据进行字符集编码或排序。
  • TEXT 存储文本数据,并且根据指定的字符集进行编码和排序。

大小限制

  • BLOB 可以存储非常大的二进制数据,通常在几个字节到几吉字节之间,具体限制取决于数据库的配置。
  • TEXT 也可以存储大量文本数据,但其大小通常受数据库配置和数据类型的限制,例如 TINYTEXTTEXTMEDIUMTEXTLONGTEXT 分别支持不同的文本大小。

索引和搜索

  • BLOB 类型的数据通常不适合用于索引和搜索,因为它们是二进制数据,不容易比较或搜索。
  • TEXT 类型的数据可以用于索引和搜索,可以执行文本搜索和模糊匹配查询。

适用场景

  • BLOB 适用于存储二进制文件或图像等二进制数据。
  • TEXT 适用于存储大段文本,如文章内容、评论、日志等。

NULL 在 MySQL 中是什么意思?

在MySQL中,NULL 是一种特殊的数据值,表示缺少值或未知值。它不等同于空字符串、零或任何其他值,而是表示数据缺失或不适用的情况。

  1. 缺失值或未知值: NULL 表示某个列的值没有被指定或未知。例如,如果你有一个存储人的出生日期的列,并且某些人的出生日期未知,你可以将这些列的值设置为 NULL。
  2. 与空字符串的区别: NULL 不同于空字符串 ('')。空字符串是一个具有零长度的字符串,而 NULL 表示未知或缺失值。在比较时,空字符串和 NULL 是不相等的。
  3. 在比较中的特殊性质: 在MySQL中,与 NULL 的比较通常需要使用IS NULLIS NOT NULL,而不是使用=<>。例如,要检查一个列是否为 NULL,你应该使用 column_name IS NULL,要检查一个列是否不为 NULL,你应该使用 column_name IS NOT NULL
  4. 在索引中的影响: 如果你在一个列上有一个索引,并且这列允许 NULL 值,那么索引会包括 NULL 值的行。这点需要注意,因为在某些情况下,你可能需要谨慎处理包含 NULL 值的索引列。
  5. 处理 NULL 值: 在查询和数据操作中,你需要考虑如何处理 NULL 值。你可以使用IFNULL()COALESCE()等函数来处理 NULL 值,以便在计算和显示中提供更有意义的结果。

索引

MySQL 索引类型有哪些?

B-Tree 索引:B-Tree(平衡树)索引是 MySQL 最常见的索引类型。它适用于等值查询、范围查询和排序操作。B-Tree 索引在 MySQL 中常见于普通索引(INDEXKEY)和唯一索引(UNIQUE)。

哈希索引:哈希索引适用于等值查询,但不适用于范围查询或排序。哈希索引在某些特定场景下可以提供非常快速的查找性能。但是,它不支持像 B-Tree 索引那样的排序功能,而且不允许有重复键值。

全文索引:全文索引用于全文搜索,它允许对文本数据进行高效的全文搜索操作。MySQL 提供了全文索引的支持,通常用于 FULLTEXT 类型的索引。

空间索引:空间索引用于存储和查询具有地理空间属性的数据,例如地理坐标、多边形区域等。MySQL 提供了空间索引的支持,通常用于 SPATIAL 类型的索引。

前缀索引:前缀索引允许您为列的一部分创建索引,而不是整个列。这可以节省存储空间并提高索引性能,但会限制索引的选择性。

复合索引:复合索引允许在多个列上创建索引,以支持多列的查询条件。复合索引可以提高多列条件查询的性能,但需要谨慎设计以确保其最佳性能。

唯一索引:唯一索引确保索引列中的值是唯一的,不允许重复值。唯一索引可以用于确保表中的数据不包含重复的值。

主键索引:主键索引是一种特殊的唯一索引,它唯一标识表中的每一行。每个表只能有一个主键索引,主键通常用于在表中唯一标识每一行。

外键索引:外键索引用于维护表之间的关联关系。外键索引通常用于确保一个表的列值与另一个表的主键或唯一索引列值相匹配。

覆盖索引:覆盖索引是一种特殊情况,其中查询可以完全通过索引来满足,而不需要访问表中的实际数据行。这可以提高查询性能,因为它减少了磁盘访问和数据传输的开销。

什么情况下设置了索引但无法使用?

  1. 数据量太小:如果你的数据库表中只有很少的数据行,数据库管理系统可能会选择不使用索引,因为在这种情况下,全表扫描可能比使用索引更快。索引的主要优势在于大型数据集中,因为它可以加快数据检索速度。
  2. 联合索引不满足最左匹配原则:在联合索引中,最左侧的字段优先匹配。因此,在创建联合索引时,where子句中使用最频繁的字段放在组合索引的最左侧。而在查询时,要想让查询条件走索引,则需满足:最左边的字段要出现在查询条件中。
  3. 索引列参与运算。
  4. 索引列参使用了函数。
  5. 错误的Like使用。模糊查询时(like语句),模糊匹配的占位符位于条件的首部。
  6. 错误使用了 or 关键字。查询条件使用or关键字,其中一个字段没有创建索引,则会导致整个查询语句索引失效;or两边为“>”和“<”范围查询时,索引失效。
  7. 两列做比较。如果两个列数据都有索引,但在查询条件中对两列数据进行了对比操作,则会导致索引失效。
  8. 不等于比较。查询条件使用不等进行比较时,需要慎重,普通索引会查询结果集占比较大时索引会失效。
  9. is not null。询条件使用is null时正常走索引,使用is not null时,不走索引。
  10. not in。查询条件使用not in时,如果是主键则走索引,如果是普通索引,则索引失效。
  11. 查询条件使用not exists时,索引失效。

什么时候不要使用索引?

小表:对于非常小的表,使用索引可能没有太大的性能提升,甚至可能导致性能下降。这是因为索引本身需要占用额外的存储空间,并且在访问小表时,扫描整个表可能比使用索引更快。

高度动态的表:如果表的数据频繁插入、更新或删除,并且索引需要频繁维护,那么索引可能会成为性能瓶颈。在这种情况下,需要仔细考虑索引的设计和维护成本。

低选择性的列:如果要在具有低选择性的列上创建索引,即该列包含大量重复值,那么索引的效果可能不佳。在这种情况下,查询优化器可能选择不使用索引,因为它不会显著提高查询性能。

频繁的大批量数据加载:在大规模数据加载或导入操作期间,索引可能会导致性能下降,因为每次插入数据时都需要更新索引。在这种情况下,可以考虑在数据加载之前暂时禁用索引,然后在加载完成后重新建立索引。

特定查询不使用索引:某些查询可能使用不到现有的索引,或者可能需要创建新的复合索引来支持。在这种情况下,需要谨慎考虑索引的创建,以确保它们对现有的查询需求有效。

频繁的索引重建:如果索引需要频繁重建(例如,由于硬件故障或维护操作),则在索引不可用时查询性能可能会受到影响。这需要考虑索引的可用性和维护成本。

事务

并发事务带来哪些问题?

  • **脏读:**脏读发生在一个事务读取了另一个事务尚未提交的数据。如果后续事务回滚,读取的数据就是无效的,导致数据不一致。
  • 不可重复读:不可重复读发生在一个事务在同一个数据项上进行多次读取,但在读取之间另一个事务修改了该数据项,导致读取的结果不一致。
  • **幻读:**幻读是一个事务在读取一系列数据时,发现另一个事务在同一系列数据上插入或删除了行,导致读取的数据不一致。
  • 丢失更新:丢失更新发生在两个事务同时读取相同数据,然后一个事务修改数据并提交,然后另一个事务也修改了相同数据并提交,导致前一个事务的修改丢失。例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。

不可重复读和幻读的区别是什么?

  • 不可重复读是指同一行数据在两次读取之间被其他事务修改,导致读取的值不一致。
  • 幻读是指同一查询在两次执行之间由于其他事务的插入、更新或删除操作导致结果集不一致,即返回的行数或内容发生变化。
  • 不可重复读关注的是同一行数据的内容变化,而幻读关注的是结果集的变化,包括行的插入、更新和删除。

事务隔离级别有哪些?MySQL的默认隔离级别是?

读未提交(Read Uncommitted)

  • 在这个隔离级别下,一个事务可以读取到其他事务尚未提交的数据。
  • 这是最低的隔离级别,不提供任何数据一致性保证。

读已提交(Read Committed)

  • 在这个隔离级别下,一个事务只能读取到已经提交的数据,不能读取到其他事务尚未提交的数据。
  • 这是大多数数据库系统的默认隔离级别,包括 MySQL(不过 MySQL 的实现稍有不同,称为"可重复读",见下文)。

可重复读(Repeatable Read)

  • 在这个隔离级别下,一个事务可以多次读取相同的数据,并且保证读取的数据不会被其他事务修改。
  • 这解决了脏读和不可重复读问题,但仍可能发生幻读。

串行化(Serializable)

  • 串行化是最高的隔离级别,它确保了完全的事务隔离,事务之间没有任何并发访问。
  • 这可以解决脏读、不可重复读和幻读问题,但可能导致性能下降,因为事务需要等待其他事务完成才能执行。
隔离级别 脏读 不可重复读 幻影读
READ-UNCOMMITTED
READ-COMMITTED ×
REPEATABLE-READ × ×
SERIALIZABLE × × ×

MySQL 的默认隔离级别是 可重复读(Repeatable Read)。这意味着在默认情况下,一个事务可以多次读取相同的数据,而不会看到其他事务正在修改的数据。

MVCC

说说什么是 MVCC?

MVCC,即多版本并发控制(Multi-Version Concurrency Control),是一种用于数据库管理系统中处理并发事务的技术。MVCC 允许多个事务同时访问和修改数据库,同时保持事务之间的隔离性,从而实现高并发性和数据一致性。

MVCC 的核心原理是什么?

MVCC(Multi-Version Concurrency Control)的核心原理是通过为每个事务创建版本或快照来管理并发访问和修改数据库,从而实现高并发性和数据一致性。以下是 MVCC 的核心原理:

版本管理:MVCC 基于版本管理的思想。每个事务在对数据库进行读取和修改操作时,都会创建一个自己的数据版本或快照。这个版本包含了事务开始时数据库的状态。

并发事务:多个事务可以同时执行,每个事务都使用自己的版本来读取和修改数据,而不会互相干扰。

读取一致性:MVCC 确保读取操作能够看到一致的数据状态。即使其他事务正在修改数据,读取操作也会获得一个自己事务开始时的一致快照,从而避免读取到不一致或脏数据。

写入冲突:当多个事务同时尝试修改相同的数据时,MVCC 使用一些策略来解决写入冲突。通常,一个事务会等待另一个事务完成,或者其中一个事务会回滚以避免数据不一致。

事务提交:当事务成功完成并提交时,它的修改会成为新的数据库版本。其他事务可以基于这个新版本创建自己的快照。

回滚和垃圾回收:当事务回滚或不再需要某个版本时,MVCC 可以清理无效的数据版本,以释放存储空间。

高并发性:MVCC 允许多个事务并发执行,因为它们不会相互干扰,每个事务都在自己的快照中工作,而不会直接修改共享数据。这提高了数据库系统的并发性和性能。

MVCC 可以为数据库解决什么问题?

MVCC是一种用于处理并发事务的数据库管理技术,它可以解决多个与并发事务相关的问题,包括以下几个主要问题:

  1. 读-写冲突:MVCC 可以解决读-写冲突的问题,允许多个事务同时读取数据库而不互相干扰。每个事务都可以获得一个一致性的数据快照,即使其他事务正在修改数据。
  2. 写-写冲突:当多个事务同时试图修改相同的数据时,MVCC 使用版本管理来解决写-写冲突。通常,一个事务会等待另一个事务完成或回滚,以避免数据的不一致性。
  3. 事务隔离:MVCC 提供了事务隔离,确保每个事务都能看到一个一致的数据库状态。这意味着事务之间不会互相干扰,每个事务都能够操作一致的数据。
  4. 读取一致性:MVCC 确保读取操作能够看到一致的数据状态,即使其他事务正在修改数据。这可以防止读取到不一致或脏数据。
  5. 并发性:MVCC 允许多个事务并发地读取和修改数据库,从而提高数据库系统的并发性和性能。事务之间不需要互斥锁定,因为它们使用各自的数据快照。
  6. 事务回滚:MVCC 允许事务回滚到之前的数据版本,而不会影响其他事务。这提供了更好的事务管理和错误恢复能力。
  7. 数据一致性:MVCC 确保数据库的数据一致性,即使在多个事务同时操作的情况下也能保持数据的完整性。
  8. 高并发性:由于每个事务都有自己的数据快照,MVCC 允许多个事务同时执行,而不会导致冲突或性能下降。

总的来说,MVCC 是一种强大的并发控制技术,它允许数据库在多个事务并发访问和修改数据时保持数据一致性和事务隔离性。

请说说 MySQL 数据库的锁?

MySQL 数据库中的锁是用于管理并发访问和修改数据的机制,以确保数据的一致性和完整性。MySQL 提供了不同类型的锁,用于不同的情况和需求:

  1. 共享锁
    • 共享锁(也称为读锁)允许多个事务同时持有锁,并且不阻止其他事务获取共享锁。多个事务可以同时读取相同的数据,而不会相互干扰。
    • 共享锁用于读取操作,通常在事务中使用 SELECT 语句时自动获得。
  2. 排他锁
    • 排他锁(也称为写锁)只允许一个事务持有锁,其他事务无法同时持有排他锁。排他锁用于写入操作,它会阻止其他事务读取或写入相同的数据,确保数据的一致性。
    • 排他锁通常在事务中使用 INSERTUPDATEDELETE 等语句时自动获得。
  3. 表锁
    • 表锁是最粗粒度的锁,它锁定整个表,阻止其他事务访问该表的任何部分。表锁适用于一些特殊情况,但通常会导致并发性下降。
    • 表锁通常用于非事务存储引擎(如 MyISAM),而不是事务性存储引擎(如 InnoDB)。
  4. 行级锁
    • 行级锁是最细粒度的锁,它允许锁定表中的单个数据行,而不是整个表。行级锁可以更好地支持并发性,因为不同事务可以同时锁定表中的不同行。
    • InnoDB 存储引擎支持行级锁,这是其事务性和高并发性的关键特性之一。
  5. 意向锁
    • 意向锁是一种辅助锁,用于表示事务打算在某个特定层次上锁定数据。它们通常用于帮助 MySQL 管理表级锁的冲突。
    • 意向锁包括意向共享锁(IS)和意向排他锁(IX),它们分别表示事务打算在某个表上获取共享锁或排他锁。

说说什么是锁升级?

MySQL 行锁只能加在索引上,如果操作不走索引,就会升级为表锁。因为 InnoDB 的行锁是加在索引上的,如果不走索引,自然就没法使用行锁了,原因是 InnoDB 是将 primary key index 和相关的行数据共同放在 B+ 树的叶节点。InnoDB 一定会有一个 primary keysecondary index 查找的时候,也是通过找到对应的 primary,再找对应的数据行。

当非唯一索引上记录数超过一定数量时,行锁也会升级为表锁。测试发现当非唯一索引相同的内容不少于整个表记录的二分之一时会升级为表锁。因为当非唯一索引相同的内容达到整个记录的二分之一时,索引需要的性能比全文检索还要大,查询语句优化时会选择不走索引,造成索引失效,行锁自然就会升级为表锁。

性能调优

MySQL 如何优化 DISTINCT?

DISTINCT 是用于从结果集中返回唯一值的关键字,但它可能会导致查询性能下降,特别是在处理大量数据时。

  1. 使用合适的索引
    • 确保查询中涉及的列上有合适的索引。索引可以帮助数据库更快地识别唯一的值,从而减少 DISTINCT 操作的时间。
  2. 使用 GROUP BY 替代 DISTINCT
    • 在某些情况下,可以使用 GROUP BY 子句来代替 DISTINCT 来获取唯一值。但要注意,这两者的行为略有不同,因此需要谨慎使用。
  3. 避免在大数据集上使用 DISTINCT
    • 在大型数据集上执行 DISTINCT 操作可能会非常耗时。如果可能的话,尽量避免在大数据表上使用 DISTINCT
  4. 使用覆盖索引
    • 如果查询仅涉及到查询列和索引列,而不需要访问实际表数据,那么可以考虑使用覆盖索引。覆盖索引是一个包含查询列的索引,可以避免访问实际表数据,从而提高查询性能。
  5. 定期优化表
    • 定期执行表优化操作,例如 OPTIMIZE TABLE,以清理不必要的碎片和优化索引结构。
  6. 考虑分区表
    • 如果数据表非常大,可以考虑将其分成多个分区表。这可以加速对特定分区的 DISTINCT 查询。

SQL 注入漏洞产生的原因有哪些?如何防止?

SQL 注入产生的原因主要是不正确地处理用户输入数据,使恶意用户能够在 SQL 查询中注入恶意代码。主要原因有如下几个:

  1. 未正确过滤用户输入: 如果应用程序未正确验证和过滤用户输入,攻击者可以在输入中插入恶意 SQL 代码。
  2. 拼接 SQL 查询字符串: 如果应用程序将用户输入直接拼接到 SQL 查询字符串中,而没有使用参数化查询或绑定变量的方式来构建查询,那么攻击者可以在输入中插入恶意代码。
  3. 不安全的数据库权限: 如果数据库用户具有过高的权限,攻击者可以在注入时执行危险的操作,如删除表或获取敏感数据。

防范措施:

  1. 使用参数化查询或绑定变量: 使用参数化查询或绑定变量的方式来构建 SQL 查询,而不是手动拼接字符串。这可以防止恶意用户插入恶意代码。不同编程语言和数据库提供了不同的方法来实现参数化查询。
  2. 过滤和验证输入数据: 在接受用户输入之前,始终进行输入验证和过滤。确保输入数据符合预期的格式和类型,并拒绝任何非法字符或输入。
  3. 最小权限原则: 为数据库用户分配最小必需的权限。不要使用具有过高权限的数据库用户来执行应用程序查询。这可以减小潜在攻击的影响。
  4. 错误处理和日志记录: 在应用程序中实现良好的错误处理机制,并记录潜在的 SQL 注入尝试。这有助于监视和识别潜在的安全问题。
  5. 使用 Web Application Firewall (WAF): 部署 Web 应用程序防火墙,它可以检测和阻止常见的 SQL 注入攻击尝试。
阅读全文