Mysql8.4参考手册走读(三)

第 10 章 优化

优化概述

优化数据库性能的方法有很多,主要包括以下几个方面:

  1. 在数据库级别进行优化:

    • 确保表格结构正确,包括选择合适的数据类型和列。
    • 设置正确的索引以使查询高效。
    • 为每个表使用适当的存储引擎,并充分利用其优势。
    • 使用适当的行格式。
    • 应用程序使用适当的锁定策略。
    • 配置内存区域的大小,使其既能缓存经常访问的数据,又不会导致物理内存过载。
  2. 在硬件级别进行优化:

    • 评估磁盘搜索、读写速度、CPU周期和内存带宽等瓶颈,并根据需要调整应用程序或重新配置服务器。
  3. 平衡便携性和性能:

    • 在可移植的MySQL中使用面向性能的SQL扩展程序,将特定于MySQL的关键字包装在注释分隔符内,以便其他SQL服务器可以忽略它们。

优化 SQL 语句

优化查询的主要注意事项包括:

  1. 检查是否可以添加索引以提高查询速度。为经常用于筛选和检索结果的列设置索引。
  2. 使用EXPLAIN语句分析查询,以确定哪些索引被使用。
  3. 避免在查询中使用低效的函数或操作,如全表扫描。
  4. 定期更新表统计信息,以便优化器能够做出更高效的决策。
  5. 学习不同存储引擎的调优技术和配置参数。
  6. 对于只读事务,优化InnoDB表的查询性能。
  7. 避免将查询转换为难以理解的形式。
  8. 如果性能问题无法解决,请调整内存区域的大小和属性,以便更高效地缓存查询结果。
  9. 处理锁定问题,确保查询不受其他会话访问相同表的影响。

EXPLAIN 联接类型

EXPLAIN 输出的列描述了如何表已联接。在 JSON 格式的输出中,可以找到这些作为属性的值。以下是连接类型的描述,从最佳顺序排序到最差的顺序:

  1. system:该表只有一行(= 系统表)。这是一个 const join 类型的特例。
  2. const:该表最多有一个匹配的行,读取位置为查询的开始。因为只有一行,此行中列中的值可视为常量。常量表非常快速,因为它们只读取一次。
  3. eq_ref:对于每个组合,从此表中读取一行前面表中的行。除了 system 和 const 类型之外,这是最佳连接类型。它用于所有部分联接使用索引,索引是 OR 索引。
  4. ref:所有具有匹配索引值的行都从中读取上一行中每个行组合的表。如果出现以下情况,则使用 ref 联接仅使用键的最左边的前缀,或者如果 key 不是 OR 索引(换句话说,如果 join 不能根据键值选择单行)。 如果使用的键仅匹配几行,则这是一个良好的连接类型。
  5. fulltext:联接是使用索引执行的。
  6. ref_or_null:此连接类型类似于 ref,但使用此外,MySQL还会对以下行进行额外搜索包含值。此联接类型优化最常用于解析子查询。
  7. index_merge:此联接类型指示索引合并优化被使用。在本例中,列在输出行中包含使用的索引列表,并包含最长的索引列表所用索引的关键部分。
  8. unique_subquery:此类型将替换为某些子查询的 eq_ref:IN value IN (SELECT primary_key FROM single_table WHERE some_expr)
  9. index_subquery:此联接类型类似于 unique_subquery。它替换子查询,但它有效对于以下形式的子查询中的非唯一索引:IN value IN (SELECT key_column FROM single_table WHERE some_expr)
  10. range:仅检索给定范围内的行,使用用于选择行的索引。输出行中的列指示使用哪个索引。
  11. index:连接类型与 ALL 相同,只是扫描索引树。这有两种方式:如果索引是查询的覆盖索引,并且可用于满足表中,仅扫描索引树。在这种情况下,该专栏说.仅索引扫描通常比 ALL 快,因为索引的大小通常小于表格数据。
  12. ALL:对每行组合进行全表扫描从前面的表格中。这通常不好,如果 table 是第一个未标记为 const 的表,在所有其他情况下通常都非常糟糕。通常,您可以通过添加索引来避免 ALL 启用基于常量从表中检索行前面表中的值或列值。

EXPLAIN 输出的列包含有关MySQL如何解析其他查询的信息。以下列表说明了可以显示在此值中的一些内容。每个项目还指示哪个JSON属性对应于特定的值。有一些属性显示为文本,而其他属性则显示为它们的值。

  1. Using where:子句用于限制哪些行与下一个表匹配或发送到客户。除非您特别打算获取或检查表中的所有行,否则可能存在问题。
  2. Using index:列信息从表中检索,仅使用索引树中的信息,而不必执行附加SEEK读取实际行。
  3. Using index condition:通过访问索引元组并对其进行测试来读取表,首先确定是否读取全表行。
  4. Using join buffer (Block Nested Loop):早期联接中的表将分批读取到加入缓冲区,然后从缓冲区使用它们的行执行与当前表的联接。
  5. Using temporary:要解析查询,MySQL需要创建一个临时表来保存结果。这通常发生在查询包含列出列的GROUP BY和ORDER BY子句不同的情况下。
  6. Using filesort:MySQL必须执行额外的操作才能了解如何检索按排序顺序排列的行。
  7. Using union(…)、Using intersect(…):这些指示显示如何索引扫描将合并index_merge连接类型。
  8. Using MRR:使用多范围读取优化读取表策略。
  9. Using sort_union(…):使用排序联合优化读取表策略。

第11章 语言结构

MySQL语言结构主要包括以下几种类型:

  1. 文本值:字符串,用于存储字符数据。
  2. 数字文字:整数、浮点数等,用于存储数值数据。
  3. 日期和时间文字:用于存储日期和时间信息。
  4. 十六进制文字:以十六进制表示的数字。
  5. 位值文本:二进制数据。
  6. 布尔文字:TRUE 或 FALSE。
  7. NULL 值:表示缺失或未知的数据。

第 12 章 字符集、排序规则、Unicode

MySQL的字符集和排序规则是数据库设计和优化中的关键因素,它们影响着数据的存储、检索以及完整性

在MySQL中,字符集定义了可用于存储字符的集合和编码方式,而排序规则(或校对规则)则定义了这些字符如何进行比较和排序。选择合适的字符集和排序规则不仅能够确保数据的准确表示,还能提高数据库的查询效率和存储性能。

MySQL支持多种字符集,如Latin1、UTF8、UTF8MB4等。其中,Latin1是一个单字节字符集,主要用于支持西欧语言,其优点是占用存储空间少,处理速度快,但不支持中文、日文等东亚字符。UTF8是一个多字节字符集,支持几乎所有的语言字符,每个字符占用1至3个字节。UTF8MB4是UTF8的超集,可以存储更多的特殊字符,包括Emoji表情符号,每个字符占用1至4个字节。

在实际应用中,选择正确的字符集至关重要。例如,如果应用主要面向中文用户且不需要支持Emoji等特殊字符,可以选择GBK字符集以节省存储空间。然而,为了支持国际化和更广泛的字符集,UTF8MB4通常是更好的选择,因为它既兼容UTF8又支持更多字符。

排序规则的选择同样重要。排序规则决定了字符之间的比较和排序方式。例如,utf8_general_ci表示不区分大小写的通用排序规则,适用于大多数情况;而utf8_bin则进行二进制比较,区分大小写并可以存储二进制内容。不同的排序规则对查询速度也有影响。一般而言,不区分大小写的排序规则(如utf8_general_ci)在校对速度上更快,但准确度稍差;而utf8_unicode_ci虽然校对速度稍慢,但准确度更高。

综上所述,理解并合理配置MySQL的字符集和排序规则是确保数据一致性和查询效率的关键。通过根据应用场景选择合适的字符集和排序规则,可以有效提升数据库的性能和数据处理的准确性。

第 13 章 数据类型

MySQL支持多种数据类型,包括数值数据类型、日期和时间数据类型、字符串数据类型、空间数据类型以及JSON数据类型。这些丰富的数据类型允许以最适合的方式存储不同类型的数据,从而优化数据库的性能和存储效率。具体如下:

  1. 数值数据类型
    • 整型数据类型:MySQL提供多种整型数据类型,包括TINYINT、SMALLINT、MEDIUMINT、INT和BIGINT。其中,TINYINT的范围为-128到127(有符号)或0到255(无符号),而BIGINT的范围最大,从-9223372036854775808到9223372036854775807(有符号)或0到18446744073709551615(无符号)。
    • 浮点数据类型:浮点类型FLOAT和DOUBLE用于存储近似数值。FLOAT使用4个字节,表示单精度浮点数,而DOUBLE使用8个字节,表示双精度浮点数。DECIMAL类型则用于存储精确的小数值,适合财务计算,可以指定精度和小数位数。
  2. 日期和时间数据类型
    • 日期类型:DATE类型用于存储日期,格式为YYYY-MM-DD,范围从1000-01-01到9999-12-31。DATETIME类型结合了日期和时间,格式为YYYY-MM-DD HH:MM:SS。TIMESTAMP则以时间戳的形式保存日期和时间,支持自动更新特性。
    • 时间类型:TIME类型用于存储时间,格式为HH:MM:SS,表示持续时间,而YEAR则用于存储年份,可以是2位或4位格式。
  3. 字符串数据类型
    • 定长和变长字符串类型:CHAR类型是定长字符串,长度在1到255个字符之间,适合存储固定长度的文本数据。VARCHAR则是变长字符串,长度在1到255个字符之间,适合存储长度可变的文本数据。
    • 二进制和文本大对象类型:BINARY和VARBINARY类似于CHAR和VARCHAR,但用于存储二进制字符串。BLOB和TEXT类型用于存储大量的文本或二进制数据,如MEDIUMBLOB、LONGBLOB等。ENUM和SET类型则用于存储枚举值和集合值。
  4. 空间数据类型
    • 几何类型:MySQL支持空间扩展,提供了如GEOMETRY、POINT、LINESTRING、POLYGON等空间数据类型,用于存储地理对象和进行空间计算。
  5. JSON数据类型
    • JSON类型:MySQL 5.7及更高版本支持JSON数据类型,允许在数据库中直接存储和操作JSON格式的数据,提供了丰富的查询和管理功能。

综上所述,MySQL通过支持多种数据类型,为各种应用场景提供了灵活、高效的数据存储解决方案。理解并正确选择和使用这些数据类型,对于优化数据库性能、提高数据管理效率至关重要。

第 15 章 SQL 语句

数据定义语句

创建数据库对象:

  • 15.1.12 CREATE DATABASE 语句 - 用于创建新的数据库。例如:CREATE DATABASE mydatabase;
  • 15.1.20 CREATE TABLE 语句 - 用于在数据库中创建新的表。例如:CREATE TABLE users (id INT, name VARCHAR(50));
  • 15.1.21 CREATE TABLESPACE 语句 - 用于创建表空间。例如:CREATE TABLESPACE mytablespace ADD DATAFILE 'mytablespace.ibd' ENGINE=InnoDB;
  • 15.1.22 CREATE TRIGGER 语句 - 用于创建触发器。例如:CREATE TRIGGER before_insert BEFORE INSERT ON users FOR EACH ROW BEGIN ... END;
  • 15.1.23 CREATE VIEW 语句 - 用于创建视图。例如:CREATE VIEW user_view AS SELECT id, name FROM users;
  • 15.1.13 CREATE EVENT 语句 - 用于创建事件。例如:CREATE EVENT myevent ON SCHEDULE EVERY 1 HOUR DO ...;
  • 15.1.14 CREATE FUNCTION 语句 - 用于创建用户自定义函数。例如:CREATE FUNCTION add_numbers(a INT, b INT) RETURNS INT BEGIN RETURN a + b; END;

修改数据库对象:

  • 15.1.3 ALTER EVENT 语句 - 用于修改事件的定义。例如:ALTER EVENT myevent ON SCHEDULE EVERY 2 HOURS;
  • 15.1.4 ALTER FUNCTION 语句 - 用于修改用户自定义函数的定义。例如:ALTER FUNCTION add_numbers(a INT, b INT) RETURNS INT BEGIN RETURN a + b + 1; END;
  • 15.1.5 ALTER INSTANCE 语句 - 用于修改实例的配置参数。例如:ALTER INSTANCE SET max_connections = 200;
  • 15.1.6 ALTER LOGFILE GROUP 语句 - 用于修改日志文件组的属性。例如:ALTER LOGFILE GROUP mygroup ADD UNDOFILE 'undofile';
  • 15.1.7 ALTER PROCEDURE 语句 - 用于修改存储过程的定义。例如:ALTER PROCEDURE myprocedure() BEGIN ... END;
  • 15.1.8 ALTER SERVER 语句 - 用于修改服务器的配置参数。例如:ALTER SERVER myserver CONNECTION_LIMIT = 1000;
  • 15.1.9 ALTER TABLE 语句 - 用于修改表的结构。例如:ALTER TABLE users ADD COLUMN email VARCHAR(100);
  • 15.1.10 ALTER TABLESPACE 语句 - 用于修改表空间的属性。例如:ALTER TABLESPACE mytablespace ENGINE=InnoDB;
  • 15.1.11 ALTER VIEW 语句 - 用于修改视图的定义。例如:ALTER VIEW user_view AS SELECT id, name, email FROM users;

删除数据库对象:

  • 15.1.24 DROP DATABASE 语句 - 用于删除数据库。例如:DROP DATABASE mydatabase;
  • 15.1.25 DROP EVENT 语句 - 用于删除事件。例如:DROP EVENT myevent;
  • 15.1.26 DROP FUNCTION 语句 - 用于删除用户自定义函数。例如:DROP FUNCTION add_numbers;
  • 15.1.27 DROP INDEX

数据操作语句

数据查询:

  • 15.2.13 SELECT 语句 - 用于从数据库中查询数据。例如:SELECT * FROM users;
  • 15.2.15 子查询 - 在查询中嵌套的查询。例如:SELECT name FROM users WHERE id IN (SELECT id FROM employees);
  • 15.2.20 WITH(通用表表达式)- 创建临时表以简化复杂查询。例如:WITH user_totals AS (SELECT user_id, COUNT(*) as total FROM orders GROUP BY user_id) SELECT u.name, t.total FROM users u JOIN user_totals t ON u.id = t.user_id;

数据修改:

  • 15.2.2 DELETE 语句 - 用于删除表中的数据。例如:DELETE FROM users WHERE id = 1;
  • 15.2.12 REPLACE 语句 - 用于插入或替换表中的数据。例如:REPLACE INTO users (id, name) VALUES (1, 'John Doe');
  • 15.2.17 UPDATE 语句 - 用于更新表中的数据。例如:UPDATE users SET name = 'Jane Doe' WHERE id = 1;

数据插入:

  • 15.2.7 INSERT 语句 - 用于向表中插入新数据。例如:INSERT INTO users (id, name) VALUES (2, 'Jane Doe');
  • 15.2.19 VALUES 语句 - 用于插入多行数据。例如:VALUES (3, 'Alice'), (4, 'Bob');

数据导入导出:

  • 15.2.6 IMPORT TABLE 语句 - 用于从文件导入数据到表中。例如:IMPORT TABLE users FROM '/path/to/users.csv';
  • 15.2.9 LOAD DATA 语句 - 用于从文件加载数据到表中。例如:LOAD DATA INFILE '/path/to/data.txt' INTO TABLE mytable;
  • 15.2.10 LOAD XML 语句 - 用于从XML文件加载数据到表中。例如:LOAD XML '/path/to/data.xml' INTO TABLE mytable;

其他操作:

  • 15.2.1 CALL 语句 - 用于调用存储过程。例如:CALL myprocedure();
  • 15.2.3 DO 语句 - 用于执行一个匿名块的SQL代码。例如:DO $$ BEGIN ... END;
  • 15.2.5 HANDLER 语句 - 用于处理SQL脚本中的错误。例如:DECLARE EXIT HANDLER FOR SQLEXCEPTION ...
  • 15.2.16 TABLE 语句 - 用于查看表的结构。例如:DESCRIBE users;
  • 15.2.18 UNION 条款 - 用于合并两个或多个查询的结果集。例如:(SELECT id FROM table1) UNION (SELECT id FROM table2);
  • 15.2.4 EXCEPT 条款 - 用于从一个查询结果集中减去另一个查询结果集。例如:(SELECT id FROM table1) EXCEPT (SELECT id FROM table2);
  • 15.2.8 INTERSECT 子句 - 用于获取两个查询结果集的交集。例如:(SELECT id FROM table1) INTERSECT (SELECT id FROM table2);
  • 15.2.14 使用 UNION、INTERSECT 和 EXCEPT 设置操作 - 用于组合查询结果集。例如:(SELECT id FROM table1) UNION (SELECT id FROM table2) INTERSECT (SELECT id FROM table3);

交易和锁定声明

15.3.1 START TRANSACTION、COMMIT 和 ROLLBACK 语句

  • START TRANSACTION:开始一个新的事务。在事务中,可以执行多个SQL操作,这些操作要么全部成功,要么全部失败。
  • COMMIT:提交当前事务,使其所做的更改成为永久更改。
  • ROLLBACK:回滚当前事务,撤销其所做的所有更改。

示例:

START TRANSACTION;
UPDATE account SET balance = balance - 100 WHERE id = 1;
UPDATE account SET balance = balance + 100 WHERE id = 2;
COMMIT; -- 如果发生错误,可以使用 ROLLBACK; 回滚事务

15.3.2 无法回滚的语句

  • 一些SQL语句是不可回滚的,因为它们不涉及数据的修改,例如SELECT、SHOW等。

15.3.3 导致隐式提交的语句

  • 当执行某些SQL语句时,会自动提交事务,无需显式调用COMMIT。例如,DDL(数据定义语言)操作(如CREATE、ALTER、DROP等)。

15.3.4 SAVEPOINT、回滚到 SAVEPOINT 和 RELEASE SAVEPOINT 语句

  • SAVEPOINT savepoint_name:在当前事务中创建一个保存点。
  • ROLLBACK TO savepoint_name:回滚到指定的保存点。
  • RELEASE SAVEPOINT savepoint_name:删除指定的保存点。

示例:

START TRANSACTION;
UPDATE account SET balance = balance - 100 WHERE id = 1;
SAVEPOINT A;
UPDATE account SET balance = balance + 200 WHERE id = 2;
SAVEPOINT B;
UPDATE account SET balance = balance - 50 WHERE id = 3;
ROLLBACK TO A; -- 回滚到保存点A
COMMIT;

15.3.5 LOCK INSTANCE FOR BACKUP 和 UNLOCK INSTANCE 语句

  • LOCK INSTANCE FOR BACKUP:锁定实例以进行备份,防止其他用户访问数据库。
  • UNLOCK INSTANCE:解锁实例,允许其他用户访问数据库。

示例:

LOCK INSTANCE FOR BACKUP;
-- 备份数据库...
UNLOCK INSTANCE;

15.3.6 LOCK TABLES 和 UNLOCK TABLES 语句

  • LOCK TABLES table_name [READ | WRITE]:锁定一个或多个表,以防止其他用户访问它们。
  • UNLOCK TABLES:解锁所有已锁定的表。

示例:

LOCK TABLES account WRITE;
-- 对account表进行操作...
UNLOCK TABLES;

15.3.7 SET TRANSACTION 语句

  • SET TRANSACTION transaction_characteristic [= value]:设置事务的特性,如隔离级别、只读状态等。

示例:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

15.3.8 XA 事务

  • XA事务是一种分布式事务处理机制,允许在多个资源管理器(如数据库)之间协调事务。它使用两阶段提交协议来确保事务的原子性。

复制语句

15.4.1 用于控制源服务器的 SQL 语句

  • START GROUP_REPLICATION:启动组复制。
  • STOP GROUP_REPLICATION:停止组复制。
  • SET GLOBAL group_replication_bootstrap_group=ON:设置全局变量,允许在没有现有组的情况下启动组复制。
  • SET GLOBAL group_replication_allow_local_disjoint_gtids_join=ON:设置全局变量,允许本地节点加入组复制,即使它们的 GTID 集合不相交。

示例:

-- 启动组复制
START GROUP_REPLICATION;

-- 停止组复制
STOP GROUP_REPLICATION;

-- 允许在没有现有组的情况下启动组复制
SET GLOBAL group_replication_bootstrap_group=ON;

-- 允许本地节点加入组复制,即使它们的 GTID 集合不相交
SET GLOBAL group_replication_allow_local_disjoint_gtids_join=ON;

15.4.2 用于控制副本服务器的 SQL 语句

  • CHANGE MASTER TO MASTER_HOST='host', MASTER_USER='user', MASTER_PASSWORD='password', MASTER_AUTO_POSITION=1:更改副本服务器的主服务器信息。
  • START SLAVE:启动副本服务器的复制进程。
  • STOP SLAVE:停止副本服务器的复制进程。
  • RESET SLAVE:重置副本服务器的复制状态。
  • RESET SLAVE ALL:重置副本服务器的所有复制状态。

示例:

-- 更改副本服务器的主服务器信息
CHANGE MASTER TO MASTER_HOST='host', MASTER_USER='user', MASTER_PASSWORD='password', MASTER_AUTO_POSITION=1;

-- 启动副本服务器的复制进程
START SLAVE;

-- 停止副本服务器的复制进程
STOP SLAVE;

-- 重置副本服务器的复制状态
RESET SLAVE;

-- 重置副本服务器的所有复制状态
RESET SLAVE ALL;

15.4.3 用于控制组复制的 SQL 语句

  • CREATE USER 'user'@'host' IDENTIFIED BY 'password';:创建用于组复制的用户。
  • GRANT REPLICATION SLAVE ON *.* TO 'user'@'host';:授予用户复制权限。
  • CHANGE MASTER TO MASTER_HOST='host', MASTER_USER='user', MASTER_PASSWORD='password', MASTER_AUTO_POSITION=1 FOR CHANNEL 'channel';:更改组复制通道的主服务器信息。
  • START GROUP_REPLICATION FOR CHANNEL 'channel';:启动指定通道的组复制。
  • STOP GROUP_REPLICATION FOR CHANNEL 'channel';:停止指定通道的组复制。
  • RESET GROUP_REPLICATION FOR CHANNEL 'channel';:重置指定通道的组复制状态。
  • RESET GROUP_REPLICATION ALL FOR CHANNEL 'channel';:重置指定通道的所有组复制状态。

示例:

-- 创建用于组复制的用户
CREATE USER 'user'@'host' IDENTIFIED BY 'password';

-- 授予用户复制权限
GRANT REPLICATION SLAVE ON *.* TO 'user'@'host';

-- 更改组复制通道的主服务器信息
CHANGE MASTER TO MASTER_HOST='host', MASTER_USER='user', MASTER_PASSWORD='password', MASTER_AUTO_POSITION=1 FOR CHANNEL 'channel';

-- 启动指定通道的组复制
START GROUP_REPLICATION FOR CHANNEL 'channel';

-- 停止指定通道的组复制
STOP GROUP_REPLICATION FOR CHANNEL 'channel';

-- 重置指定通道的组复制状态
RESET GROUP_REPLICATION FOR CHANNEL 'channel';

-- 重置指定通道的所有组复制状态
RESET GROUP_REPLICATION ALL FOR CHANNEL 'channel';

准备语句

15.5.1 PREPARE 语句
PREPARE语句用于创建一个预处理语句,它可以包含占位符(问号?),这些占位符稍后可以通过EXECUTE语句填充具体的值。预处理语句可以提高性能,因为它们只需要解析一次,然后可以多次执行。

示例:

PREPARE stmt FROM 'SELECT * FROM users WHERE age > ?';

在这个例子中,我们创建了一个名为stmt的预处理语句,它包含了一个占位符?

15.5.2 EXECUTE 语句
EXECUTE语句用于执行预处理语句,并填充占位符的值。

示例:

SET @age = 30;
EXECUTE stmt USING @age;

在这个例子中,我们首先设置了一个变量@age的值为30,然后使用EXECUTE语句执行预处理语句stmt,并将@age的值传递给占位符?

15.5.3 DEALLOCATE PREPARE 语句
DEALLOCATE PREPARE语句用于释放预处理语句占用的资源。在执行完预处理语句后,应该使用DEALLOCATE PREPARE语句来清理资源。

示例:

DEALLOCATE PREPARE stmt;

在这个例子中,我们释放了名为stmt的预处理语句所占用的资源。

第 16 章 MySQL 数据字典

16.1 数据字典架构
MySQL Server 的数据字典架构采用集中式存储,将所有数据库对象的信息存储在一个统一的地方。这样可以简化管理和维护,同时也提高了性能。在以前的MySQL版本中,字典数据存储在元数据文件中,这些文件是非事务性的,可能导致数据不一致的问题。而在MySQL 8.4及更高版本中,已经删除了基于文件的元数据存储,改为使用事务性的数据字典。

16.2 删除基于文件的元数据存储
为了提高数据字典的性能和可靠性,MySQL 8.4及更高版本已经删除了基于文件的元数据存储。这意味着所有的字典数据都存储在内存中,而不是磁盘上。这样可以确保数据的一致性和崩溃恢复能力。

16.3 字典数据的事务性存储
在MySQL 8.4及更高版本中,数据字典采用事务性存储,这意味着所有的字典操作都是原子性的,可以保证数据的一致性和完整性。此外,事务性存储还可以提高系统的性能,因为不需要频繁地从磁盘读取数据。

16.4 字典对象缓存
为了提高查询性能,MySQL Server对数据字典对象进行了缓存。这意味着经常访问的对象会被缓存在内存中,从而减少了磁盘I/O操作。这种缓存机制可以提高查询速度,特别是在处理大量数据库对象时。

16.5 INFORMATION_SCHEMA和数据字典集成
MySQL Server的INFORMATION_SCHEMA表提供了一种简单、改进的方式来访问数据字典信息。这些表包含了关于数据库、表、列等对象的详细信息。通过查询INFORMATION_SCHEMA表,用户可以获取到与数据字典相关的各种信息,而无需直接访问底层的数据字典。

16.6 序列化字典信息(SDI)
序列化字典信息(SDI)是一种将数据字典信息导出为二进制格式的方法。这种格式可以方便地在不同的MySQL实例之间传输数据字典信息,从而实现数据的迁移和备份。在MySQL 8.4及更高版本中,可以使用mysqldump工具导出SDI文件。

16.7 数据字典用法差异
在不同版本的MySQL中,数据字典的实现和使用方式可能有所不同。例如,在MySQL 8.0及更高版本中,引入了原子DDL(原子数据定义语句),这使得创建、修改或删除数据库对象时可以保证数据的一致性。而在较早的版本中,这些操作可能需要额外的步骤来确保数据的完整性。

16.8 数据字典限制
尽管MySQL Server的数据字典具有许多优点,但在某些情况下可能会受到限制。例如,数据字典的大小受到内存限制,如果字典过大,可能会导致内存不足的问题。此外,数据字典的操作可能会受到锁的限制,尤其是在高并发环境下。因此,在使用数据字典时,需要权衡其优缺点,并根据实际需求进行优化。

第 17 章 InnoDB 存储引擎

InnoDB多版本控制

InnoDB多版本并发控制(MVCC)在处理二级索引时,与处理聚集索引的方式有所不同。在聚集索引中,记录会在原地更新,并且其隐藏的系统列指向撤消先前日志条目,这样可以重建记录的版本。而在二级索引中,记录不包含隐藏系统列,也不会就地更新。

当更新二级索引列时,旧的二级索引记录会被标记为删除,同时插入新的记录。带有删除标记的记录最终会被清除。当辅助索引记录被标记为删除或二级索引页被较新的事务更新时,需要查找聚集索引中的数据库记录。在这种情况下,会在聚簇索引中检查记录,并从撤消日志中检索记录的正确版本,如果在读取事务后修改了记录。

如果二级索引记录被标记为删除,或者二级索引页由较新的事务更新,那么不会使用覆盖索引技术。而是从聚簇索引中返回值。但是,如果启用了索引条件下推(ICP)优化,部分条件可以使用仅包含索引中的字段,MySQL服务器仍然会将其推送到存储引擎进行评估。如果没有找到匹配的记录,避免了聚集索引查找。如果找到了匹配的记录,即使在已删除标记的记录中,也会在聚簇索引中查找记录。

InnoDB磁盘结构

InnoDB磁盘结构主要包括以下几个部分:

17.6.1 表格
在InnoDB中,表格是数据库中存储数据的基本单位。每个表格由多个行组成,每个行包含多个列。表格可以拥有不同的存储引擎,如InnoDB、MyISAM等。

17.6.2 索引
索引是用于快速检索数据的数据结构。在InnoDB中,有两种类型的索引:聚集索引和辅助索引(二级索引)。聚集索引是一种特殊的索引,它包含了表中的所有数据。而辅助索引则只包含索引列的值和主键值。

17.6.3 表空间
表空间是InnoDB中用于存储表格和索引的物理文件。默认情况下,InnoDB使用一个共享表空间来存储所有表格和索引。但是,也可以通过配置参数innodb_file_per_table来为每个表格创建一个独立的表空间文件。

17.6.4 双写缓冲区
双写缓冲区(Doublewrite Buffer)是InnoDB中的一个缓冲区,用于防止由于操作系统或存储子系统的故障导致的页面损坏。当InnoDB向表空间写入数据时,它会先将数据写入双写缓冲区,然后再将数据写入实际的表空间文件中。这样,即使发生故障,也可以从双写缓冲区中恢复数据。

17.6.5 重做日志
重做日志(Redo Log)是InnoDB中用于记录事务操作的日志文件。当事务提交时,InnoDB会将事务的操作记录到重做日志中。如果发生故障,可以通过重做日志来恢复未完成的事务。

17.6.6 撤消日志
撤消日志(Undo Log)是InnoDB中用于记录事务回滚信息的日志文件。当事务需要回滚时,InnoDB会使用撤消日志中的信息来恢复到事务开始前的状态。撤消日志还用于实现多版本并发控制(MVCC),以支持一致性读和避免锁定读取行的开销。

InnoDB锁定

InnoDB存储引擎支持多种锁类型,这些锁类型用于实现事务的隔离性,确保数据的一致性和并发控制。以下是一些主要的锁类型及其用途:

共享锁和独占锁

  • 共享锁(S锁):允许一个事务读取一行数据,同时允许其他事务也读取同一行数据,但不允许进行写操作。
  • 独占锁(X锁):允许一个事务对一行数据进行写操作,同时阻止其他事务读取或写入同一行数据。

意向锁

  • 意向共享锁(IS锁):表示一个事务计划在未来对表中的某些行设置共享锁。
  • 意向独占锁(IX锁):表示一个事务计划在未来对表中的某些行设置独占锁。
  • 意向锁主要用于表级锁和行级锁之间的兼容性检查。

记录锁

  • 记录锁:锁定索引记录,防止其他事务对该记录进行插入、更新或删除操作。

间隙锁

  • 间隙锁:锁定索引记录之间的间隙,防止其他事务在这些间隙中插入新的索引记录。

Next-Key 锁

  • Next-Key 锁:是索引记录上的记录锁和该记录前的间隙锁的组合,用于防止其他事务在索引顺序中插入新记录。

插入意图锁

  • 插入意图锁:一种特殊类型的间隙锁,由尝试插入间隙中的事务设置,表示有意在该间隙中插入新记录。

AUTO-INC 锁

  • AUTO-INC 锁:一种特殊的表级锁,用于处理包含自动增量列的表的插入操作,确保自动增量值的顺序生成。

空间索引的谓词锁

  • 空间索引的谓词锁:用于支持对具有空间索引的表的隔离级别,通过对查询中使用的最小边界矩形(MBR)值设置谓词锁来实现。

这些锁类型及其机制共同保证了InnoDB存储引擎在处理并发事务时的数据一致性和隔离性。通过适当的锁定策略,InnoDB能够有效地管理多个事务同时访问相同数据的情况,避免数据冲突和不一致。

InnoDB事务模型

事务隔离级别

事务隔离是数据库中的一个重要概念,它决定了多个事务同时执行时如何相互影响。InnoDB提供了四种事务隔离级别:READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。默认的隔离级别是REPEATABLE READ。

在REPEATABLE READ隔离级别下,同一事务中的一致读取会读取第一次读取时的数据。这意味着,如果您发出几个普通的(非锁定)SELECT语句,这些SELECT语句彼此之间也是一致的结果。对于锁定读取(带有FOR UPDATE或FOR SHARE的SELECT、UPDATE或DELETE语句),锁定取决于语句是否使用唯一索引,并带有唯一搜索条件,或范围类型搜索条件。

在READ COMMITTED隔离级别下,每个一致的读取都会设置并读取自己的新快照。对于锁定读取(带有SELECT或FOR UPDATE的语句)、UPDATE语句和DELETE语句,仅锁定索引记录,而不是它们前面的空白,因此允许自由地在锁定的记录旁边插入新记录。间隙锁定仅用于外键约束检查和重复密钥检查。

在READ UNCOMMITTED隔离级别下,SELECT语句以非锁定方式执行,但可能更早地访问行的版本。这可能导致脏读,即读取到其他事务尚未提交的数据。

在SERIALIZABLE隔离级别下,所有普通SELECT语句都转换为SELECT … FOR SHARE(如果禁用了自动提交)。这个级别类似于REPEATABLE READ,但强制将所有普通SELECT语句阻止,如果其他事务已修改所选行,禁用自动提交。

总之,事务隔离级别决定了多个事务同时执行时如何相互影响。不同的隔离级别适用于不同的应用场景,需要根据实际需求选择合适的隔离级别。

InnoDB中不同SQL语句设置的锁

锁定读取、UPDATE或DELETE操作通常会在处理SQL语句时为扫描到的每个索引记录设置记录锁。无论语句中是否有排除该行的条件,都不会记住确切的条件,只知道哪些索引范围被扫描过。这些锁通常是下一个键锁,也会阻止在记录前的“间隙”中插入。但是,可以明确禁用间隙锁定,这样就不会使用下一个键锁定。有关更多信息,请参见第17.7.1节,“InnoDB锁定”。事务隔离级别也会影响设置哪些锁;请参见第17.7.2.1节,“事务隔离级别”。

如果使用二级索引进行搜索,并且要设置的索引记录锁是独占的,还会检索相应的聚集索引记录并在其上设置锁。

如果没有适合你语句的索引,而MySQL必须扫描整个表来处理语句,那么表中的每一行都会被锁定,这反过来又会阻止其他用户向表中插入所有行。创建良好的索引很重要,以便你的查询不会扫描不必要的更多行。

InnoDB按如下方式设置特定类型的锁。

SELECT … FROM是一个一致读取,读取数据库的快照,除非事务隔离级别设置为SERIALIZABLE,否则不设置任何锁。对于SERIALIZABLE级别,搜索将在遇到的索引记录上设置共享的下一个键锁。然而,只有当使用唯一索引锁定行以搜索唯一行时,才需要索引记录锁。

使用唯一索引的SELECT … FOR UPDATE和SELECT … FOR SHARE语句获取扫描行的锁,并释放那些不符合结果集包含条件的行的锁(例如,如果它们不符合子句中给出的标准)。然而,在某些情况下,由于在查询执行期间结果行与其原始来源之间的关系丢失,行可能不会立即解锁。例如,在UNION中,来自表的已扫描(和锁定)的行可能会在评估它们是否符合结果集之前插入临时表。在这种情况下,临时表中的行与原始表中的行的关系丢失,后者的行直到查询执行结束才会解锁。

对于锁定读取(带有或的SELECT)、UPDATE和DELETE语句,采取的锁取决于语句是使用唯一索引与唯一搜索条件还是范围类型搜索条件。

对于具有唯一搜索条件的唯一索引,只锁定找到的索引记录,而不是之前的间隙。

对于其他搜索条件和非唯一索引,将锁定扫描的索引范围,使用间隙锁或下一个键锁阻止其他会话插入范围内的间隙。有关间隙锁和下一个键锁的信息,请参见第17.7.1节,“InnoDB锁定”。

对于搜索遇到的索引记录,SELECT … FOR UPDATE阻止其他会话执行SELECT … FOR SHARE或在某些事务隔离级别下进行读取。一致读取忽略存在于读取视图中的记录上设置的任何锁。

UPDATE … WHERE …在搜索遇到的每条记录上设置一个独占的下一个键锁。然而,只有当使用唯一索引锁定行以搜索唯一行时,才需要索引记录锁。

当UPDATE修改聚集索引记录时,会对受影响的二级索引记录采取隐式锁。UPDATE操作在执行重复检查扫描以插入新的二级索引记录以及插入新的二级索引记录时,也会对受影响的二级索引记录采取共享锁。

DELETE FROM … WHERE …在搜索遇到的每条记录上设置一个独占的下一个键锁。然而,只有当使用唯一索引锁定行以搜索唯一行时,才需要索引记录锁。

INSERT在插入的行上设置独占锁。这个锁是一个索引记录锁,不是下一个键锁(也就是说,没有间隙锁),并且不会阻止其他会话在插入的行之前的间隙中插入。

在插入行之前,设置了称为插入意向间隙锁的间隙锁类型。这种锁以这样的方式表示插入的意图:如果多个事务正在插入同一个索引间隙,只要它们不是在同一个间隙内的相同位置插入,就无需相互等待。假设有值为4和7的索引记录。尝试插入值5和6的单独事务会在获得插入行的独占锁之前,用插入意向锁锁定4和7之间的间隙,但因为它们的行是非冲突的,所以不会互相阻塞。

如果发生重复键错误,则会在重复的索引记录上设置共享锁。如果另一个会话已经拥有独占锁,这种共享锁的使用可能导致死锁,如果有多个会话试图插入同一行。如果另一个会话删除了行,可能会发生这种情况。假设一个表具有以下结构:InnoDBt1

CREATE TABLE t1 (i INT, PRIMARY KEY (i)) ENGINE = InnoDB;
现在假设三个会话按顺序执行以下操作:

会话1:

START TRANSACTION;
INSERT INTO t1 VALUES(1);
会话2:

START TRANSACTION;
INSERT INTO t1 VALUES(1);
会话3:

START TRANSACTION;
INSERT INTO t1 VALUES(1);
会话1:

ROLLBACK;

会话1的第一个操作获取了行的独占锁。会话2和会话3的操作都导致了一个重复键错误,它们都请求对该行的一个共享锁。当会话1回滚时,它释放了该行的独占锁,排队的共享锁请求为会话2和会话3被授权。此时,会话2和会话3发生死锁:由于另一个会话持有的共享锁,两者都无法获取该行的独占锁。

如果表中已经包含一个键值为1的行,且三个会话按顺序执行以下操作,类似的情况也会发生:

会话1:

START TRANSACTION;
DELETE FROM t1 WHERE i = 1;
会话2:

START TRANSACTION;
INSERT INTO t1 VALUES(1);
会话3:

START TRANSACTION;
INSERT INTO t1 VALUES(1);
会话1:

COMMIT;
会话1的第一个操作获取了行的独占锁。会话2和会话3的操作都导致了一个重复键错误,它们都请求对该行的一个共享锁。当会话1提交时,它释放了该行的独占锁,排队的共享锁请求为会话2和会话3被授权。此时,会话2和会话3发生死锁:由于另一个会话持有的共享锁,两者都无法获取该行的独占锁。

INSERT … ON DUPLICATE KEY UPDATE与简单的INSERT不同,当发生重复键错误时,会在要更新的行上放置一个独占锁而不是共享锁。对于重复的主键值,会采取独占索引记录锁。对于重复的唯一键值,会采取独占下一个键锁。

如果没有唯一键冲突,REPLACE就像INSERT一样执行。否则,会在要替换的行上放置一个独占下一个键锁。

INSERT INTO T SELECT … FROM S WHERE …对插入的每一行设置了一个独占索引记录锁(没有间隙锁)。如果事务隔离级别是READ COMMITTED,则在上执行搜索作为一致读取(不设置锁)。否则,在行上设置共享的下一个键锁。在这种情况下,必须设置锁:在使用基于语句的二进制日志进行前滚恢复时,每个SQL语句必须以原始方式完全相同地执行。

CREATE TABLE … SELECT …使用共享的下一个键锁或作为一致读取来执行SELECT,如同INSERT … SELECT一样。

当在结构或中使用时,在来自表的行上设置共享的下一个键锁。SELECTREPLACE INTO t SELECT … FROM s WHERE …UPDATE t … WHERE col IN (SELECT … FROM s …)InnoDBs

在初始化表上先前指定的列时,InnoDB会在与该列相关联的索引末尾设置一个独占锁。AUTO_INCREMENT

当innodb_autoinc_lock_mode=0时,使用一种特殊的表锁定模式,在该模式下,访问自动增量计数器时获取并保持锁到当前SQL语句结束(而不是整个事务结束)。其他客户端在持有表锁时无法插入表格。“批量插入”在innodb_autoinc_lock_mode=1时表现相同的行为。在innodb_autoinc_lock_mode=2时不使用表级锁。有关更多信息,请参见第17.6.1.6节,“InnoDB中的AUTO_INCREMENT处理”。InnoDBAUTO-INCAUTO-INCAUTO-INC

InnoDB获取先前初始化列的值时不设置任何锁。AUTO_INCREMENT

如果在表上定义了约束,任何需要检查约束条件的插入、更新或删除都会在其检查约束时查看的记录上设置共享的记录级锁。在约束失败的情况下,也会设置这些锁。FOREIGN KEYInnoDB

LOCK TABLES设置表锁,但它是高于设置这些锁的层的更高MySQL层。如果(默认)并且autocommit = 0,InnoDB知道关于表锁的信息,而上面的MySQL层知道关于行级锁的信息。InnoDBinnodb_table_locks = 1InnoDB

否则,'s的自动死锁检测无法检测到涉及此类表锁的死锁。此外,因为在这种情况下更高MySQL层不知道行级锁,所以有可能在一个会话当前拥有行级锁的表上获得表锁。然而,这不会危及事务完整性,正如第17.7.5.2节“死锁检测”所讨论的。InnoDB

如果(默认),LOCK TABLES在每个表上获取两个锁。除了MySQL层上的表锁外,它还获取一个表锁。为避免获取表锁,设置。如果不获取表锁,即使表的一些记录被其他事务锁定,LOCK TABLES也会完成。innodb_table_locks=1InnoDBInnoDBinnodb_table_locks=0InnoDB

在MySQL 8.4中,对于通过LOCK TABLES … WRITE显式锁定的表,innodb_table_locks=0没有效果。但是,它对于通过LOCK TABLES … WRITE隐式锁定(例如,通过触发器)或通过LOCK TABLES … READ锁定的表有影响。

当事务提交或中止时,事务持有的所有锁都会被释放。因此,在autocommit=1模式下调用LOCK TABLES并没有多大意义,因为获得的表锁会立即被释放。InnoDBInnoDBInnoDB

在事务中间,您不能锁定额外的表,因为LOCK TABLES执行了一个隐式的COMMIT和UNLOCK TABLES。

幻行

当一个事务在执行相同的查询多次时,如果第二次查询返回了第一次未返回的行,这些新增的行就被称为“幻像”行。这种现象发生在事务处理中,由于不同时间点查询到的行集不同而产生的问题。

以一个例子来说明:假设有一个表child,其上有一个列id被索引。现在你想要读取并锁定所有id值大于100的行,以便后续更新它们。你可以执行如下查询:

SELECT * FROM child WHERE id > 100 FOR UPDATE;

这个查询会从id值为100之后的第一条记录开始扫描索引。假设表中包含id值为90和102的行。如果在扫描范围内的索引记录上设置的锁不锁定间隙中的插入(即90和102之间的间隙),则另一个会话可以在该间隙中插入一个新行,比如id为101的行。如果在同一个事务中再次执行相同的SELECT查询,你会发现结果集中多出了一个id为101的新行,这就是所谓的“幻像”行。

为了防止这种情况发生,InnoDB使用了一种叫做next-key locking的算法,它将索引行锁定与间隙锁定结合起来。当InnoDB搜索或扫描表索引时,它会对遇到的每个索引记录加上共享锁或独占锁。这样,行级锁实际上就是索引记录锁。此外,索引记录上的下一个键锁定还会影响该索引记录之前的间隙。换句话说,下一个键锁是索引记录锁加上前面间隙上的间隙锁。这就意味着,如果一个会话持有某个索引记录的共享锁或独占锁,其他会话就不能在该索引记录之前的间隙中插入新的索引记录。

在扫描索引时,InnoDB还可以锁定索引中最后一条记录之后的间隙。这种情况发生在前面的示例中:为了防止在表中插入任何大于100的值,设置的锁包括在值102之后的间隙上的一个锁。

通过使用下一键锁定,你可以在应用程序中实现唯一性检查:如果你在共享模式下读取数据,并且没有看到要插入行的重复项,那么你就可以安全地插入你的行,并知道在下一键锁定的保护下,你的行的后继者同时被阻止了插入重复项。因此,下一键锁定使你能够“锁定”表中尚不存在的东西。

间隙锁定是可以被禁用的,如第17.7.1节“InnoDB锁定”所述。但是禁用间隙锁定可能会导致幻像问题,因为其他会话可以在间隙中插入新行,而间隙锁定已经被禁用。

死锁

死锁是指两个或多个事务相互等待对方释放资源,导致它们都无法继续执行的情况。当事务锁定多个行时,可能会发生死锁,尤其是在更新操作中。死锁可能发生在以下情况下:

  1. 两个或多个事务尝试以不同的顺序锁定相同的资源。
  2. 一个事务持有一些资源的锁,而另一个事务需要这些资源才能继续执行。
  3. 事务长时间持有锁,导致其他事务无法获得所需的锁。

为了避免死锁的发生,可以采取以下措施:

  1. 尽量保持事务的简短和简单,避免长时间持有锁。
  2. 按照相同的顺序访问资源,例如,始终先锁定表A,然后锁定表B。
  3. 使用较低的隔离级别,如READ COMMITTED,可以减少死锁的可能性。
  4. 设置合适的锁超时时间,以便在发生死锁时能够及时回滚事务。
  5. 定期检查并优化数据库设计和查询,以减少并发冲突的可能性。

如果死锁确实发生了,MySQL会自动检测到并选择一个事务进行回滚,以解除死锁状态。可以通过查看错误日志或使用SHOW ENGINE INNODB STATUS命令来获取有关死锁的详细信息。在某些情况下,可能需要手动干预来解决死锁问题,例如重新设计应用程序逻辑或调整事务处理顺序。

InnoDB INFORMATION_SCHEMA表

InnoDB INFORMATION_SCHEMA是MySQL数据库中的一个特殊模式,它提供了关于InnoDB存储引擎的元数据信息。这些信息包括表、索引、事务、锁定、缓冲池、指标和临时表等。以下是对这些表的解释和查询示例:

  1. InnoDB INFORMATION_SCHEMA关于压缩的表(17.15.1):
    这个表包含了关于InnoDB表空间压缩的信息。例如,可以查询某个表是否启用了压缩以及压缩的状态。

查询示例:

SELECT table_name, compression FROM information_schema.innodb_table_stats WHERE name = 'your_database/your_table';
  1. InnoDB INFORMATION_SCHEMA事务和锁定信息(17.15.2):
    这个表包含了关于InnoDB事务和锁定的信息。例如,可以查询当前活动的事务和锁定情况。

查询示例:

SELECT * FROM information_schema.innodb_trx;
  1. InnoDB INFORMATION_SCHEMA模式对象表(17.15.3):
    这个表包含了关于InnoDB模式对象的信息,如表、索引、列等。例如,可以查询某个表的结构信息。

查询示例:

SELECT * FROM information_schema.columns WHERE table_schema = 'your_database' AND table_name = 'your_table';
  1. InnoDB INFORMATION_SCHEMA FULLTEXT 索引表(17.15.4):
    这个表包含了关于InnoDB全文索引的信息。例如,可以查询某个表的全文索引信息。

查询示例:

SELECT * FROM information_schema.innodb_ft_index_cache WHERE word = 'your_search_word';
  1. InnoDB INFORMATION_SCHEMA缓冲池表(17.15.5):
    这个表包含了关于InnoDB缓冲池的信息。例如,可以查询缓冲池的大小、使用情况等。

查询示例:

SELECT * FROM information_schema.innodb_buffer_pool_stats;
  1. InnoDB INFORMATION_SCHEMA指标表(17.15.6):
    这个表包含了关于InnoDB性能指标的信息。例如,可以查询最近的事务数量、每秒事务数等。

查询示例:

SELECT * FROM information_schema.innodb_metrics;
  1. InnoDB INFORMATION_SCHEMA 临时表信息表(17.15.7):
    这个表包含了关于InnoDB临时表的信息。例如,可以查询临时表的使用情况。

查询示例:

SELECT * FROM information_schema.innodb_temp_table_info;
  1. 从INFORMATION_SCHEMA检索 InnoDB 表空间元数据。文件(17.15.8):
    这个部分描述了如何从INFORMATION_SCHEMA中检索InnoDB表空间的元数据。例如,可以查询表空间的大小、使用情况等。

查询示例:

SELECT * FROM information_schema.innodb_sys_tablespaces;

InnoDB 限制

InnoDB是MySQL数据库的一个存储引擎,它有一些限制,包括:

  1. 一个表最多可以包含1017列。虚拟生成的列也包含在这个限制中。
  2. 一个表最多可以包含64个二级索引。
  3. 对于使用DYNAMIC或COMPRESSED行格式的表,索引键前缀长度限制为3072字节。对于使用REDUNDANT或COMPACT行格式的表,索引键前缀长度限制为767字节。如果超过这个限制,将返回错误。
  4. 多列索引最多允许16列。超过这个限制将返回错误。
  5. 最大行大小取决于页面大小和可变长度列的数量。例如,默认的innodb_page_size为16KB时,最大行大小约为8000字节。但是,对于64KB的页面大小,最大行大小约为16000字节。LONGBLOB和LONGTEXT列的大小必须小于4GB,并且总行大小(包括BLOB和TEXT列)必须小于4GB。
  6. 最大表或表空间大小受服务器的文件系统限制,可以施加最大文件大小小于内部64 TiB大小限制的大小。例如,Linux上的ext4文件系统的最大值为16 TiB,因此最大表或表空间大小变为16 TiB而不是64 TiB。另一个例子是FAT32文件系统,它的最大值为4 GB。
  7. 如果需要更大的系统表空间,可以使用几个较小的数据文件,或者跨文件/表和常规分发表数据表空间数据文件。
  8. 日志的组合最大大小为512GB。
  9. 最小表空间大小略大于10MB。最大表空间大小取决于页面大小。
  10. 一个实例最多支持2^32个(4294967296)表空间,其中有少量为撤消表和临时表保留的表空间。
  11. 共享表空间最多支持2^32(4294967296)个表。
  12. 表空间文件的路径(包括文件名)不能超出Windows上的限制。在Windows 10之前,限制为260字符。从Windows 10版本1607开始,可以从常见的Win32文件和目录功能中受益,但必须启用新行为。
  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吴代庄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值