MySQL InnoDB File-Per-Table表空间

InnoDB File-Per-Table表空间
过去,所有InnoDB表和索引都存储在系统表空间中。这种整体的方法针对的是完全专用于数据库处理的机器,通过精心规划的数据增长,分配给MySQL的任何磁盘存储永远不会被用于其他用途。InnoDB的file-per-table表空间特性提供了一个更灵活的替代方案,每个InnoDB表及其索引都存储在一个单独的.ibd数据文件中。每个这样的.ibd数据文件代表一个单独的表空间。这个特性是由innodb_file_per_table配置选项控制的,在MySQL 5.6.6及更高版本中默认启用。

file-per-table表空间的优点
.当truncate或drop存储在file-per-table表空间中的表时,可以回收磁盘空间。truncate或drop存储在共享系统表空间中的表会在系统表空间数据文件(ibdata文件)内部创建空闲空间,这些空间只能用于新的InnoDB数据。

.在存储在file-per-table表空间文件中的表上运行TRUNCATE TABLE操作会更快。

.您可以将特定的表存储在单独的存储设备上,以实现I/O优化、空间管理或备份目的。在以前的版本中,您必须将整个数据库目录移动到其他驱动器,并在MySQL数据目录中创建符号链接。在MySQL 5.6.6及更高版本中,你可以使用
create table… data directory=absolute_path_to_directory。

.你可以运行OPTIMIZE TABLE来压缩或重新创建一个file-per-table表空间。当你运行一个OPTIMIZE TABLE时,InnoDB会创建一个新的.ibd文件,该文件带有一个临时名称,只使用存储实际数据所需的空间。当优化完成后,InnoDB会删除旧的.ibd文件,并用新文件替换它。如果以前的.ibd文件显著增长,但实际数据只占其大小的一部分,那么运行OPTIMIZE TABLE可以回收未使用的空间。

.你可以移动单个InnoDB表,而不是整个数据库

.你可以将InnoDB表从一个MySQL实例复制到另一个实例(称为可迁移表空间特性)。

.在file-per-table表空间中创建的表使用Barracuda文件格式。Barracuda文件格式支持压缩和动态行格式等特性

.可以使用动态行格式为具有大型BLOB或TEXT列的表启用更高效的存储。

.file-per-table表空间可以在发生损坏、服务器无法重启或备份和二进制日志不可用时提高成功恢复的机会并节省时间。

.在复制或备份表时,file-per-table表空间可以方便地报告每个表的状态。

.可以在文件系统级别监控表大小,而不需要访问MySQL。

.当innodb_flush_method设置为O_DIRECT时,普通的Linux文件系统不允许并发写入单个文件。因此,使用file-per-table表空间和innodb_flush_method可能会提高性能。

.系统表空间存储数据字典和undo日志,受InnoDB表空间大小限制。使用file-per_table表空间,每个表都有自己的表空间,这为增长提供了空间。

file-per-table表空间的潜在缺点
.使用file-per-table表空间,每个表可能有未使用的空间,这些空间只能由同一表的行使用。如果管理不当,可能会造成空间的浪费。

.fsync操作必须在每个打开的表上运行,而不是单个文件上。因为每个文件都有一个单独的fsync操作,所以对多个表的写操作不能合并成一个单独的I/O操作。这可能需要InnoDB执行更多的fsync操作。

.mysqld必须为每个表保留一个打开的文件句柄,如果在file-per-table表空间中有很多表,这可能会影响性能。

.使用了更多的文件描述符

.innodb_file_per_table在MySQL 5.6.6及更高版本中是默认启用的。如果向后兼容MySQL 5.5或5.1是一个问题,你可以考虑禁用它。禁用innodb_file_per_table功能可以防止在ALTER TABLE重新创建InnoDB表(ALGORITHM=COPY)时,阻止alter table将InnoDB表从系统表空间移动到单独的.ibd文件中。

例如,当重构InnoDB表的聚集索引时,表会使用innodb_file_per_table的当前设置重新创建。此行为在添加或删除InnoDB二级索引时不适用。当不重建表而创建二级索引时,无论当前的innodb_file_per_table设置是什么,索引都被存储在与表数据相同的文件中。此行为也不适用于使用CREATE TABLE…TABLESPACE或ALTER TABLE …TABLESPACE语法添加到系统表空间中的表。这些表不受innodb_file_per_table设置的影响。

.如果许多表都在增长,可能会出现更多的碎片,这可能会影响DROP TABLE和表扫描性能。但是,在管理碎片时,将文件放在它们自己的表空间中可以提高性能。

.在删除file-per-table表空间时会扫描缓冲池,对于大小为几十gb的缓冲池来说,这可能需要几秒钟的时间。扫描是用一个宽的内部锁执行的,这可能会延迟其他操作。系统表空间中的表不受影响。

.innodb_autoextend_increment变量定义了自动扩展的共享表空间文件满时的扩展大小(以MB为单位),但不适用于file-per-table表空间文件,不管是否设置了innodb_autoextend_increment,这些文件都是自动扩展的。最初的扩展是少量的,之后扩展以4MB的增量出现。

启用与禁用file-per-table表空间
innodb_file_per_table选项默认是启用的。

为了在启动时设置innodb_file_per_table选项,可以在启动服务时使用–innodb_file_per_table命令行选项或者在my.cnf文件中[mysqld]部分增加以下一行内容:

[mysqld]
innodb_file_per_table=1

你也可以在服务器运行时动态设置innodb_file_per_table:

mysql> SET GLOBAL innodb_file_per_table=1;
Query OK, 0 rows affected (0.00 sec)

启用innodb_file_per_table时,可以将InnoDB表存储在tbl_name.ibd文件。不像MyISAM存储引擎,它有单独的tbl_name.MYD和tbl_name.MYI文件用于索引和数据,InnoDB将数据和索引一起存储在一个.ibd文件中。仍然像往常一样创建tbl_name.frm文件。

如果在启动选项中禁用innodb_file_per_table并重启服务器或者使用set global命令来禁用它,除非你显式的使用create table … tablespace选项将表存放在file-per-table表空间或通用表空间否则innodb将在系统表空间创建新表。

你总是可以读取和写入任何InnoDB表,不管file-per-table设置情况。

如果要将表从系统表空间移动到自己的表空间,需要修改innodb_file_per_table的设置,然后重新创建表:

mysql> SET GLOBAL innodb_file_per_table=1;
mysql> ALTER TABLE table_name ENGINE=InnoDB;

使用CREATE TABLE…TABLESPACE或ALTER TABLE…TABLESPACE语法添加表到系统表空间不受innodb_file_per_table设置的影响。要将这些表从系统表空间移动到file-per-table表空间,必须使用ALTER TABLE…TABLESPACE语法。

InnoDB总是需要系统表空间,因为它把它的内部数据字典和undo日志放在那里。.ibd文件不够InnoDB操作。

当一个表从系统表空间移到它自己的.ibd文件时,组成系统表空间的数据文件保持相同的大小。InnoDB表以前占用的空间可以被新的InnoDB数据重用,但是不会被操作系统回收使用。当将较大的InnoDB表移出系统表空间(磁盘空间有限)时,你可能更喜欢启用innodb_file_per_table并使用mysqldump命令重新创建整个实例。如上所述,使用CREATE TABLE…TABLESPACE或者ALTER TABLE…表空间语法不受innodb_file_per_table设置的影响。这些桌子必须单独移动。

在数据目录外创建逐file-per-table表空间
要在MySQL数据目录之外的特定位置创建一个新的InnoDB file-per-table表空间,使用有data directory = absolute_path_to_directory子句的CREATE TABLE语句的来实现。

提前计划位置,因为您不能在ALTER TABLE语句中使用DATA DIRECTORY子句。您指定的目录可以位于具有特定性能或容量特征的另一个存储设备上,例如快速SSD或大容量HDD。

在目标目录中,MySQL创建一个与数据库名称对应的子目录,在该子目录中为新表创建一个.ibd文件。在MySQL DATADIR目录下的数据库目录中,MySQL创建了一个table_name.Isl文件包含表路径名。.isl文件被MySQL视为一个符号链接。(InnoDB表不支持使用实际的符号链接。)

下面的例子演示了如何在MySQL数据目录外创建一个file-per-table表空间。它显示了在指定目录中创建的.ibd,以及在MySQL数据目录下的数据库目录中创建的.isl。

mysql> use mysql
Database changed
mysql> show variables like 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+
1 row in set (0.01 sec)


mysql> create table t_cs(c1 int primary key) data directory='/data';
Query OK, 0 rows affected (0.22 sec)


[root@localhost mysql]# pwd
/data/mysql
[root@localhost mysql]# ls -lrt
总用量 96
-rw-r-----. 1 mysql mysql 98304 3月   8 16:09 t_cs.ibd

[root@localhost mysql]# ls -lrt t_cs*
-rw-r-----. 1 mysql mysql 8556 3月   8 16:09 t_cs.frm
-rw-r-----. 1 mysql mysql   20 3月   8 16:09 t_cs.isl

你也可以使用CREATE TABLE…TABLESPACE与DATA DIRECTORY子句结合,在MySQL数据目录之外创建一个file-per-table表空间。为此,你必须指定innodb_file_per_table作为表空间名。

mysql> create table t_cs_3(c1 int primary key) tablespace=innodb_file_per_table data directory='/data';
Query OK, 0 rows affected (0.28 sec)

[root@localhost mysql]# ls -lrt t_cs_2*
-rw-r-----. 1 mysql mysql 98304 3月   8 16:14 t_cs_2.ibd

[root@localhost mysql]# ls -lrt t_cs_2*
-rw-r-----. 1 mysql mysql 8556 3月   8 16:14 t_cs_2.frm
-rw-r-----. 1 mysql mysql   22 3月   8 16:14 t_cs_2.isl

使用这个方法时,你不需要启用innodb_file_per_table。

使用说明:
.MySQL最初保存的.ibd文件是打开的,防止您卸载设备,但如果服务器繁忙,可能最终会关闭表。小心不要在MySQL运行时意外地卸载外部设备,或者在设备断开连接时启动MySQL。当关联的.ibd文件丢失时,试图访问表会导致严重错误,需要重新启动服务器。

如果.ibd文件仍然不在预期的路径上,服务器重启可能会失败。在本例中,手动删除数据库目录中的table_name.isl文件重新启动后,执行DROPTABLE命令删除.frm文件,并从数据字典中删除该表的信息。

.在将表存放在NFS挂载的卷上之前,请查看在使用NFS和MySQL中列出的潜在问题。

.如果您使用LVM快照、文件复制或其他基于文件的机制来备份.ibd文件,请始终使用FLUSH TABLES…FOR EXPORT语句,以确保在备份发生之前将缓存在内存中的所有更改刷新到磁盘。

.DATA DIRECTORY子句是一种支持替代符号链接的方法,符号链接一直存在问题,从来没有被支持用于单独的InnoDB表。

MySQL 修改InnoDB重做日志文件的数量或大小

修改InnoDB重做日志文件的数量或大小
修改你的InnoDB重做日志文件的数量或大小,请执行以下步骤:
1.停止MySQL服务器,并确保它没有错误地关闭

mysql> show variables like 'innodb_log_file%';
+---------------------------+----------+
| Variable_name             | Value    |
+---------------------------+----------+
| innodb_log_file_size      | 50331648 |
| innodb_log_files_in_group | 2        |
+---------------------------+----------+
2 rows in set (0.00 sec)


[root@localhost ~]# service mysqld stop
Shutting down MySQL.... SUCCESS!

2.编辑my.cnf以更改日志文件配置。如果需要修改日志文件大小,请配置innodb_log_file_size。要增加日志文件的数量,可以配置

innodb_log_files_in_group。

[mysql@localhost mysql]$ vi my.cnf
....
innodb_log_file_size=100m
innodb_log_files_in_group=3

3.重新启动MySQL服务器
如果InnoDB检测到innodb_log_file_size大小与重做日志文件大小不同,它会写一个日志检查点,关闭并删除旧的日志文件,创建新的大小的志文件,并打开新的日志文件。

[root@localhost ~]# service mysqld start
Starting MySQL.................................. SUCCESS!


日志文件显示如下:

[mysql@localhost mysql]$ tail -f mysql.err
2022-03-02T02:44:15.775252Z 0 [Warning] Insecure configuration for --secure-file-priv: Current value does not restrict location of generated files. Consider setting it to a valid, non-empty path.
2022-03-02T02:44:15.775476Z 0 [Note] /mysqlsoft/mysql/bin/mysqld (mysqld 5.7.26-log) starting as process 613 ...
2022-03-02T02:44:15.787224Z 0 [Note] InnoDB: PUNCH HOLE support available
2022-03-02T02:44:15.787311Z 0 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
2022-03-02T02:44:15.787376Z 0 [Note] InnoDB: Uses event mutexes
2022-03-02T02:44:15.787395Z 0 [Note] InnoDB: GCC builtin __atomic_thread_fence() is used for memory barrier
2022-03-02T02:44:15.787411Z 0 [Note] InnoDB: Compressed tables use zlib 1.2.11
2022-03-02T02:44:15.788175Z 0 [Note] InnoDB: Number of pools: 1
2022-03-02T02:44:15.788515Z 0 [Note] InnoDB: Using CPU crc32 instructions
2022-03-02T02:44:15.793577Z 0 [Note] InnoDB: Initializing buffer pool, total size = 128M, instances = 1, chunk size = 128M
2022-03-02T02:44:15.812360Z 0 [Note] InnoDB: Completed initialization of buffer pool
2022-03-02T02:44:15.817437Z 0 [Note] InnoDB: If the mysqld execution user is authorized, page cleaner thread priority can be changed. See the man page of setpriority().
2022-03-02T02:44:15.862640Z 0 [Note] InnoDB: Highest supported file format is Barracuda.
2022-03-02T02:44:16.043532Z 0 [Warning] InnoDB: Resizing redo log from 2*3072 to 3*6400 pages, LSN=2494312
2022-03-02T02:44:16.169341Z 0 [Warning] InnoDB: Starting to delete and rewrite log files.
2022-03-02T02:44:16.200462Z 0 [Note] InnoDB: Setting log file ./ib_logfile101 size to 100 MB
2022-03-02T02:44:16.200745Z 0 [Note] InnoDB: Progress in MB:
 100
2022-03-02T02:44:26.280622Z 0 [Note] InnoDB: Setting log file ./ib_logfile1 size to 100 MB
2022-03-02T02:44:26.281005Z 0 [Note] InnoDB: Progress in MB:
 100
2022-03-02T02:44:37.028157Z 0 [Note] InnoDB: Setting log file ./ib_logfile2 size to 100 MB
2022-03-02T02:44:37.029053Z 0 [Note] InnoDB: Progress in MB:
 100
2022-03-02T02:44:47.532468Z 0 [Note] InnoDB: Renaming log file ./ib_logfile101 to ./ib_logfile0
2022-03-02T02:44:47.532675Z 0 [Warning] InnoDB: New log files created, LSN=2494312
2022-03-02T02:44:47.533502Z 0 [Note] InnoDB: Creating shared tablespace for temporary tables
2022-03-02T02:44:47.533760Z 0 [Note] InnoDB: Setting file './ibtmp1' size to 12 MB. Physically writing the file full; Please wait ...
2022-03-02T02:44:48.119249Z 0 [Note] InnoDB: File './ibtmp1' size is now 12 MB.
2022-03-02T02:44:48.121693Z 0 [Note] InnoDB: 96 redo rollback segment(s) found. 96 redo rollback segment(s) are active.
2022-03-02T02:44:48.121740Z 0 [Note] InnoDB: 32 non-redo rollback segment(s) are active.
2022-03-02T02:44:48.122598Z 0 [Note] InnoDB: Waiting for purge to start
2022-03-02T02:44:48.172771Z 0 [Note] InnoDB: page_cleaner: 1000ms intended loop took 32356ms. The settings might not be optimal. (flushed=0 and evicted=0, during the time.)
2022-03-02T02:44:48.186082Z 0 [Note] InnoDB: 5.7.26 started; log sequence number 2494303
2022-03-02T02:44:48.186431Z 0 [Note] InnoDB: Loading buffer pool(s) from /mysqldata/mysql/ib_buffer_pool
2022-03-02T02:44:48.186776Z 0 [Note] Plugin 'FEDERATED' is disabled.
2022-03-02T02:44:48.366419Z 0 [Note] Found ca.pem, server-cert.pem and server-key.pem in data directory. Trying to enable SSL support using them.
2022-03-02T02:44:48.367248Z 0 [Warning] CA certificate ca.pem is self signed.
2022-03-02T02:44:48.369110Z 0 [Note] Server hostname (bind-address): '*'; port: 3306
2022-03-02T02:44:48.371083Z 0 [Note] IPv6 is available.
2022-03-02T02:44:48.371145Z 0 [Note]   - '::' resolves to '::';
2022-03-02T02:44:48.371213Z 0 [Note] Server socket created on IP: '::'.
2022-03-02T02:44:48.430720Z 0 [Note] InnoDB: Buffer pool(s) load completed at 220302 10:44:48
2022-03-02T02:44:48.434777Z 0 [Note] Failed to start slave threads for channel ''
2022-03-02T02:44:48.452218Z 0 [Note] Event Scheduler: Loaded 0 events
2022-03-02T02:44:48.452566Z 0 [Note] /mysqlsoft/mysql/bin/mysqld: ready for connections.
Version: '5.7.26-log'  socket: '/mysqlsoft/mysql/mysql.sock'  port: 3306  Source distribution

其中以下部分显示了服务器重置日志文件的大小与数量

2022-03-02T02:44:16.043532Z 0 [Warning] InnoDB: Resizing redo log from 2*3072 to 3*6400 pages, LSN=2494312
2022-03-02T02:44:16.169341Z 0 [Warning] InnoDB: Starting to delete and rewrite log files.
2022-03-02T02:44:16.200462Z 0 [Note] InnoDB: Setting log file ./ib_logfile101 size to 100 MB
2022-03-02T02:44:16.200745Z 0 [Note] InnoDB: Progress in MB:
 100
2022-03-02T02:44:26.280622Z 0 [Note] InnoDB: Setting log file ./ib_logfile1 size to 100 MB
2022-03-02T02:44:26.281005Z 0 [Note] InnoDB: Progress in MB:
 100
2022-03-02T02:44:37.028157Z 0 [Note] InnoDB: Setting log file ./ib_logfile2 size to 100 MB
2022-03-02T02:44:37.029053Z 0 [Note] InnoDB: Progress in MB:
 100
2022-03-02T02:44:47.532468Z 0 [Note] InnoDB: Renaming log file ./ib_logfile101 to ./ib_logfile0
2022-03-02T02:44:47.532675Z 0 [Warning] InnoDB: New log files created, LSN=2494312


[mysql@localhost ~]$ mysql -uroot -pxxzx7817600 mysql
mysql: [Warning] Using a password on the command line interface can be insecure.
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.26-log Source distribution

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show variables like 'innodb_log_file%';
+---------------------------+-----------+
| Variable_name             | Value     |
+---------------------------+-----------+
| innodb_log_file_size      | 104857600 |
| innodb_log_files_in_group | 3         |
+---------------------------+-----------+
2 rows in set (0.01 sec)

MySQL 减少InnoDB系统表空间的大小

减少InnoDB系统表空间的大小
不能从系统表空间中删除数据文件。若要减少系统表空间大小,请使用此过程:
1.使用mysqldump将所有的包括MySQL数据库中的InnoDB表dump出来,在5.6当前版本中,包括5张InnoDB表:

[mysql@localhost ~]$ mysql -uroot -pxxzx7817600 mysql
mysql: [Warning] Using a password on the command line interface can be insecure.
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.26-log Source distribution

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show variables like 'innodb_data%';
+-----------------------+------------------------------------+
| Variable_name         | Value                              |
+-----------------------+------------------------------------+
| innodb_data_file_path | ibdata1:76M;ibdata2:50M:autoextend |
| innodb_data_home_dir  |                                    |
+-----------------------+------------------------------------+
2 rows in set (0.01 sec)

mysql> SELECT TABLE_NAME from INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='mysql' and ENGINE='InnoDB';
+---------------------------+
| TABLE_NAME                |
+---------------------------+
| engine_cost               |
| gtid_executed             |
| help_category             |
| help_keyword              |
| help_relation             |
| help_topic                |
| innodb_index_stats        |
| innodb_table_stats        |
| plugin                    |
| server_cost               |
| servers                   |
| slave_master_info         |
| slave_relay_log_info      |
| slave_worker_info         |
| time_zone                 |
| time_zone_leap_second     |
| time_zone_name            |
| time_zone_transition      |
| time_zone_transition_type |
+---------------------------+
19 rows in set (0.00 sec)



[mysql@localhost ~]$ mysqldump  -uroot -pxxzx7817600 --all-databases > all_db_dump_20220223.sql
mysqldump: [Warning] Using a password on the command line interface can be insecure.

2.停止MySQL服务器

[mysql@localhost ~]$ mysqladmin -uroot -pxxzx7817600 shutdown
mysqladmin: [Warning] Using a password on the command line interface can be insecure.

3.删除所有已经存在的表空间文件(*.ibd),包括ibdata和ib_log文件。不要忘记删除MySQL数据库中的*.ibd文件。

[mysql@localhost mysql]$ find ./mysql -name "*.ibd"
./mysql/plugin.ibd
./mysql/servers.ibd
./mysql/help_topic.ibd
./mysql/help_category.ibd
./mysql/help_relation.ibd
./mysql/help_keyword.ibd
./mysql/time_zone_name.ibd
./mysql/time_zone.ibd
./mysql/time_zone_transition.ibd
./mysql/time_zone_transition_type.ibd
./mysql/time_zone_leap_second.ibd
./mysql/innodb_table_stats.ibd
./mysql/innodb_index_stats.ibd
./mysql/slave_relay_log_info.ibd
./mysql/slave_master_info.ibd
./mysql/slave_worker_info.ibd
./mysql/gtid_executed.ibd
./mysql/server_cost.ibd
./mysql/engine_cost.ibd
[mysql@localhost mysql]$ find ./mysql -name "*.ibd"    | xargs -n 1 rm -f

[mysql@localhost mysql]$ rm -rf ibdata*
[mysql@localhost mysql]$ rm -rf ib_log*
[mysql@localhost mysql]$ ls -lrt ibdata*
ls: 无法访问ibdata*: 没有那个文件或目录
[mysql@localhost mysql]$ ls -lrt ib_log*
ls: 无法访问ib_log*: 没有那个文件或目录

4.删除InnoDB表的.frm文件

[mysql@localhost mysql]$ rm -rf mysql/plugin..frm
[mysql@localhost mysql]$ rm -rf mysql/servers..frm
[mysql@localhost mysql]$ rm -rf mysql/help_topic..frm
[mysql@localhost mysql]$ rm -rf mysql/help_category..frm
[mysql@localhost mysql]$ rm -rf mysql/help_relation.frm
[mysql@localhost mysql]$ rm -rf mysql/help_keyword.frm
[mysql@localhost mysql]$ rm -rf mysql/time_zone_name.frm
[mysql@localhost mysql]$ rm -rf mysql/time_zone.frm
[mysql@localhost mysql]$ rm -rf mysql/time_zone_transition.frm
[mysql@localhost mysql]$ rm -rf mysql/time_zone_transition_type.frm
[mysql@localhost mysql]$ rm -rf mysql/time_zone_leap_second.frm
[mysql@localhost mysql]$ rm -rf mysql/innodb_table_stats.frm
[mysql@localhost mysql]$ rm -rf mysql/innodb_index_stats.frm
[mysql@localhost mysql]$ rm -rf mysql/slave_relay_log_info.frm
[mysql@localhost mysql]$ rm -rf mysql/slave_master_info.frm
[mysql@localhost mysql]$ rm -rf mysql/slave_worker_info.frm
[mysql@localhost mysql]$ rm -rf mysql/gtid_executed.frm
[mysql@localhost mysql]$ rm -rf mysql/server_cost.frm
[mysql@localhost mysql]$ rm -rf mysql/engine_cost.frm

5.配置一个新表空间

[mysql@localhost mysql]$ vi my.cnf
.......
innodb_data_file_path = ibdata1:10M:autoextend

6.重启MySQL服务器

[root@localhost ~]# service mysqld start
Starting MySQL......... SUCCESS!

7.导入dump文件

[mysql@localhost ~]$ mysql -uroot -pxxzx7817600 < all_db_dump_20220223.sql
mysql: [Warning] Using a password on the command line interface can be insecure.

[mysql@localhost ~]$ mysql -uroot -pxxzx7817600 mysql
mysql: [Warning] Using a password on the command line interface can be insecure.
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.26-log Source distribution

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show variables like 'innodb_data%';
+-----------------------+------------------------+
| Variable_name         | Value                  |
+-----------------------+------------------------+
| innodb_data_file_path | ibdata1:10M:autoextend |
| innodb_data_home_dir  |                        |
+-----------------------+------------------------+
2 rows in set (0.01 sec)

InnoDB系统表空间的文件变回原来的ibdata1了

mysql> SELECT TABLE_NAME from INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='mysql' and ENGINE='InnoDB';
+---------------------------+
| TABLE_NAME                |
+---------------------------+
| engine_cost               |
| gtid_executed             |
| help_category             |
| help_keyword              |
| help_relation             |
| help_topic                |
| innodb_index_stats        |
| innodb_table_stats        |
| plugin                    |
| server_cost               |
| servers                   |
| slave_master_info         |
| slave_relay_log_info      |
| slave_worker_info         |
| time_zone                 |
| time_zone_leap_second     |
| time_zone_name            |
| time_zone_transition      |
| time_zone_transition_type |
+---------------------------+
19 rows in set (0.01 sec)

注意:如果您的数据库只使用InnoDB引擎,那么可能更简单的方法是转储所有数据库,停止服务器,删除所有数据库和InnoDB日志文件,重新启动服务器,并导入转储文件。

MySQL 增加InnoDB系统表空间大小

增加InnoDB系统表空间大小
增加InnoDB系统表空间大小的最简单的方法是从一开始就配置为自动扩展。在表空间定义中为最后一个数据文件指定autoextend属性。当InnoDB用完空间时,会自动增加64MB的文件大小。可以通过设置innodb_autoextend_increment系统变量的值来更改增量大小,该变量以兆字节为单位度量。

mysql> show variables like 'innodb_autoextend_increment';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| innodb_autoextend_increment | 64    |
+-----------------------------+-------+
1 row in set (0.01 sec)

通过添加另一个数据文件,可以按定义的数量扩展系统表空间:
1.关闭MySQL服务器

2.如果上一个数据文件是用autoextend关键字定义的,那么根据它实际增长的大小,将其定义更改为使用固定大小。检查数据文件的大小,将其四舍四入到最接近的1024*1024字节(= 1MB)的倍数,并在innodb_data_file_path中显式指定这个四舍五入的大小。

3.在innodb_data_file_path的末尾添加一个新的数据文件,可以选择使该文件自动扩展。只有innodb_data_file_path中的最后一个数据文件可以被指定为自动扩展。

4.重新启动MySQL服务器。

例如,这个表空间只有一个自动扩展的数据文件ibdata1

mysql> show variables like 'innodb_data%';
+-----------------------+------------------------+
| Variable_name         | Value                  |
+-----------------------+------------------------+
| innodb_data_file_path | ibdata1:12M:autoextend |
| innodb_data_home_dir  |                        |
+-----------------------+------------------------+
2 rows in set (0.00 sec)

假设这个数据文件随着时间的推移增长到76MB。下面是修改原始数据文件以使用固定大小并添加新的自动扩展数据文件后的配置行

innodb_data_home_dir =
innodb_data_file_path =  ibdata1:76M;ibdata2:50M:autoextend

当您向系统表空间配置添加一个新的数据文件时,请确保文件名没有引用现有的文件。当您重启服务器时,InnoDB会创建并初始化该文件

a.关闭MySQL服务器

[root@localhost ~]# service mysqld stop
Shutting down MySQL.. SUCCESS!

b.检查数据文件的大小

[mysql@localhost mysql]$ du -sh ibdata1
76M     ibdata1

c.在innodb_data_file_path的末尾添加一个新的数据文件,可以选择使该文件自动扩展。

innodb_data_file_path =  ibdata1:76M;ibdata2:50M:autoextend

d.重启MySQL服务器

[root@localhost ~]# service mysqld start
Starting MySQL..... SUCCESS!

[mysql@localhost ~]$ mysql -uroot -pxxzx7817600 mysql
mysql: [Warning] Using a password on the command line interface can be insecure.
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.26-log Source distribution

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show variables like 'innodb_data%';
+-----------------------+------------------------------------+
| Variable_name         | Value                              |
+-----------------------+------------------------------------+
| innodb_data_file_path | ibdata1:76M;ibdata2:50M:autoextend |
| innodb_data_home_dir  |                                    |
+-----------------------+------------------------------------+
2 rows in set (0.01 sec)

[root@localhost mysql]# ls -lrt ibdata*
-rw-r-----. 1 mysql mysql 52428800 2月  23 11:13 ibdata2
-rwxr-xr-x. 1 mysql mysql 79691776 2月  23 11:13 ibdata1

MySQL 配置索引页的合并阈值

配置索引页的合并阈值
您可以为索引页配置MERGE_THRESHOLD值。如果一个索引页的“page-full”百分比低于MERGE_THRESHOLD值,当一个行被删除或当一个行被UPDATE 操作缩短时,InnoDB会尝试合并这个索引页和相邻的索引页。默认的MERGE_THRESHOLD值是50,这是以前的硬编码值。MERGE_THRESHOLD最小值为1,最大值为50。

当索引页的页满百分比低于50%(默认的MERGE_THRESHOLD设置)时,InnoDB会尝试将索引页与相邻页合并。如果两个页面都接近50%的满,那么在页面合并后不久就会发生页面分割。如果频繁发生这种合并-分割行为,则会对性能产生不利影响。为了避免频繁的合并分割,你可以降低MERGE_THRESHOLD值,这样InnoDB尝试页面合并的百分比就会降低。以较低的页满百分比合并页面会在索引页中留下更多的空间,并有助于减少合并-分割行为。

可以为一个表或单个索引定义索引页的MERGE_THRESHOLD。为单个索引定义的MERGE_THRESHOLD值优先于为表定义的MERGE_THRESHOLD值。如果未定义,MERGE_THRESHOLD值默认为50。

设置表的MERGE_THRESHOLD
可以使用CREATE TABLE语句的table_option COMMENT子句为一个表设置MERGE_THRESHOLD值。例如:

CREATE TABLE t1 (
id INT,
KEY id_index (id)
) COMMENT='MERGE_THRESHOLD=45';

还可以使用ALTER TABLE的table_option COMMENT子句为现有表设置MERGE_THRESHOLD值

CREATE TABLE t1 (
id INT,
KEY id_index (id)
);

ALTER TABLE t1 COMMENT='MERGE_THRESHOLD=40';

为单个索引设置MERGE_THRESHOLD
要为单个索引设置MERGE_THRESHOLD值,可以使用带有CREATE TABLE、ALTER TABLE或CREATE INDEX的index_option COMMENT子句,如下面的示例所示:
.使用CREATE TABLE为单个索引设置MERGE_THRESHOLD:

mysql> CREATE TABLE t1 (
    -> id INT,
    -> KEY id_index (id) COMMENT 'MERGE_THRESHOLD=40'
    -> );
Query OK, 0 rows affected (0.11 sec)

.使用ALTER TABLE为单个索引设置MERGE_THRESHOLD:

mysql> CREATE TABLE t1 (
    -> id INT,
    -> KEY id_index (id)
    -> );
ALTER TABLE t1 DROP KEY id_index;
ALTER TABLE t1 ADD KEY id_index (id) COMMENT 'MERGE_THRESHOLD=40';Query OK, 0 rows affected (0.17 sec)

mysql> ALTER TABLE t1 DROP KEY id_index;
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE t1 ADD KEY id_index (id) COMMENT 'MERGE_THRESHOLD=40';
Query OK, 0 rows affected (0.09 sec)
Records: 0  Duplicates: 0  Warnings: 0

使用CREATE INDEX为单个索引设置MERGE_THRESHOLD:

mysql> CREATE TABLE t1 (id INT);
Query OK, 0 rows affected (0.14 sec)

mysql> CREATE INDEX id_index ON t1 (id) COMMENT 'MERGE_THRESHOLD=40';
Query OK, 0 rows affected (0.11 sec)
Records: 0  Duplicates: 0  Warnings: 0

不能在索引级别修改GEN_CLUST_INDEX的MERGE_THRESHOLD值,GEN_CLUST_INDEX是InnoDB在创建InnoDB表时,在没有主键或唯一键索引的情况下创建的聚集索引。只能通过设置表的MERGE_THRESHOLD来修改GEN_CLUST_INDEX的MERGE_THRESHOLD值

查询索引的MERGE_THRESHOLD值
当前索引的MERGE_THRESHOLD值可以通过查询INNODB_SYS_INDEXES表获得。例如:

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES WHERE NAME='id_index' \G
*************************** 1. row ***************************
       INDEX_ID: 265
           NAME: id_index
       TABLE_ID: 267
           TYPE: 0
       N_FIELDS: 1
        PAGE_NO: 4
          SPACE: 269
MERGE_THRESHOLD: 40
1 row in set (0.00 sec)

如果使用table_option COMMENT子句显式定义,可以使用SHOW CREATE TABLE查看表的MERGE_THRESHOLD值

mysql> SHOW CREATE TABLE t1 \G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `id` int(11) DEFAULT NULL,
  KEY `id_index` (`id`) COMMENT 'MERGE_THRESHOLD=40'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

在索引级别定义的MERGE_THRESHOLD值优先于为表定义的MERGE_THRESHOLD值。如果未定义,MERGE_THRESHOLD默认为50% (MERGE_THRESHOLD=50,这是以前的硬编码值。

同样,如果使用index_option COMMENT子句显式地定义,也可以使用SHOW INDEX查看索引的MERGE_THRESHOLD值:

mysql> show index from t1 \G
*************************** 1. row ***************************
        Table: t1
   Non_unique: 1
     Key_name: id_index
 Seq_in_index: 1
  Column_name: id
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment: MERGE_THRESHOLD=40
1 row in set (0.00 sec)

测量MERGE_THRESHOLD设置的效果:

INNODB_METRICS表提供了两个计数器,可以用来衡量MERGE_THRESHOLD设置对索引页合并的影响。

mysql> SELECT NAME, COMMENT FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME like '%index_page_merge%';
+-----------------------------+----------------------------------------+
| NAME                        | COMMENT                                |
+-----------------------------+----------------------------------------+
| index_page_merge_attempts   | Number of index page merge attempts    |
| index_page_merge_successful | Number of successful index page merges |
+-----------------------------+----------------------------------------+
2 rows in set (0.00 sec)

当降低MERGE_THRESHOLD值时,目标是:
.页面合并尝试和成功合并的次数更少
.尝试合并和成功合并页面的次数相同

太小的MERGE_THRESHOLD设置由于大量的空页面空间导致大量的数据文件。

MySQL 配置InnoDB配置非持久优化器统计信息参数

配置非持久优化器统计信息参数
本节介绍如何配置非持久优化器统计信息。当innodb_stats_persistent=OFF或使用STATS_PERSISTENT=0创建或修改单个表时,优化器统计信息不会被持久化到磁盘。相反,统计信息存储在内存中,并且在服务器关闭时丢失。统计数据还由某些操作在某些条件下定期更新。

从MySQL 5.6.6开始,默认情况下,优化器统计数据被持久化到磁盘上,由innodb_stats_persistent配置选项启用。

优化器数据更新
在以下情况出现时非持久化的优化器统计信息会被更新:
.执行analyze table

.运行show table status,show index,或者在innodb_stats_on_metadata选项被启用时查询information_schema.tables或information_schema.statistics表。

MySQL 5.6.6中,当持久化优化器统计信息被启用时,innodb_stats_on_metadata默认设置为OFF。启用innodb_stats_on_metadata可能会降低具有大量表或索引的模式的访问速度,并降低涉及InnoDB表的查询的执行计划的稳定性。innodb_stats_on_metadata使用SET语句全局配置。set global innodb_stats_on_metadata=ON

innodb_stats_on_metadata只适用于优化器统计信息配置为非持久化(当innodb_stats_persistent被禁用时)。

.启动mysql客户端时启用–auto-rehash选项,这是默认设置。auto-rehash选项会打开所有InnoDB表,打开表的操作会导致统计数据重新计算。为了提高mysql客户端的启动和更新统计信息时间,你可以使用–disable-auto-rehash选项关闭auto-rehash。自动auto-rehash特性允许交互用户自动完成数据库、表和列名的命名。

.表第一次打开。

.InnoDB检测到有1 / 16的表在上次统计数据更新后被修改。

配置采样页面数
MySQL查询优化器使用关于键分布的估计统计信息,根据索引的相对选择性为执行计划选择索引。当InnoDB更新优化器统计数据时,它会从表上的每个索引中随机取样,以估计索引的基数。(这种技术被称为随机潜水。)

为了控制统计信息评估的质量(从而为查询优化器提供更好的信息),可以使用参数innodb_stats_transient_sample_pages更改抽样页面的数量。默认的抽样页面数是8,这可能不足以产生准确的评估,导致查询优化器的索引选择很差。这种技术对于大型表和连接中使用的表尤其重要。对这样的表进行不必要的全表扫描可能会造成严重的性能问题。

当innodb_stats_transient_sample_pages =0时,innodb_stats_persistent的值会影响所有InnoDB表和索引的索引采样。当您更改索引样本大小时,请注意以下潜在的重大影响。
.小值像1或2可以导致不精确的基数评估

.增加innodb_stats_transient_sample_pages的值可能需要更多的磁盘读取。大于8(比如100)的值会导致打开表或执行SHOW table STATUS所需的时间显著放缓。

.优化器可能会根据索引选择性的不同估计选择非常不同的查询计划

无论innodb_stats_transient_sample_pages的值是什么,设置该选项并保持该值。选择一个值,它可以为数据库中的所有表提供合理准确的估计,而不需要过多的I/O。因为除了在执行ANALYZE TABLE时,统计数据会在其他时间自动重新计算,所以增加索引样本大小,运行ANALYZE TABLE,然后再次减少样本大小是没有意义的。

较小的表通常比较大的表需要更少的索引样本。如果你的数据库有很多大的表,考虑使用一个更大的innodb_stats_transient_sample_pages值。

评估InnoDB表analyze table的复杂度
InnoDB表的ANALYZE TABLE复杂度依赖于:
.采样的页面数,由innodb_stats_persistent_sample_pages定义

.表中索引列的数目

.分区数。如果表没有分区,则认为分区数为1。

使用这些参数,估计ANALYZE TABLE复杂度的近似公式是
innodb_stats_persistent_sample_pages的值*表中索引的列数*分区数

通常,结果值越大,ANALYZE TABLE的执行时间就越长

innodb_stats_persistent_sample_pages定义了在全局级别上采样的页面数量。要设置单个表的采样页数,请使用有STATS_SAMPLE_PAGES选项的CREATE TABLE或ALTER TABLE的语句。

如果innodb_stats_persistent=OFF,则由innodb_stats_transient_sample_pages定义采样的页面数

要了解估算ANALYZE TABLE复杂度的更深入的方法,请考虑以下示例:
在大O符号中,ANALYZE TABLE的复杂度被描述为:

O(n_sample
* (n_cols_in_uniq_i
+ n_cols_in_non_uniq_i
+ n_cols_in_pk * (1 + n_non_uniq_i))
* n_part)

.n_sample是采样的页面数(由innodb_stats_persistent_sample_pages定义)

.n_cols_in_uniq_i是所有唯一索引中所有列的总数(不计算主键列)

.n_cols_in_non_uniq_i是所有非唯一索引中所有列的总数

.n_cols_in_pk是主键中的列数(如果没有定义主键,InnoDB会在内部创建一个单列主键)

.n_non_uniq_i是表中非唯一索引的个数

.n_part是分区的数量。如果没有定义分区,则将表视为单个分区。

现在,考虑下面的表(表t),它有一个主键(2列)、一个唯一索引(2列)和两个非唯一索引(各有两列):

mysql> CREATE TABLE t (
    -> a INT,
    -> b INT,
    -> c INT,
    -> d INT,
    -> e INT,
    -> f INT,
    -> g INT,
    -> h INT,
    -> PRIMARY KEY (a, b),
    -> UNIQUE KEY i1uniq (c, d),
    -> KEY i2nonuniq (e, f),
    -> KEY i3nonuniq (g, h)
    -> );
Query OK, 0 rows affected (0.13 sec)

对于上述算法所需的列和索引数据,查询mysql.innodb_index_stats来查看表t的持久索引统计信息。n_diff_pfx%显示了每个索引列的统计信息。
例如,列a和列b用于计算主键索引。对于非唯一索引,除了用户定义的列外,还要统计主键列(a,b)。

mysql> select index_name, stat_name, stat_description
    -> from mysql.innodb_index_stats
    -> where
    -> database_name='mysql' and
    -> table_name='t' and
    -> stat_name like 'n_diff_pfx%';
+------------+--------------+------------------+
| index_name | stat_name    | stat_description |
+------------+--------------+------------------+
| PRIMARY    | n_diff_pfx01 | a                |
| PRIMARY    | n_diff_pfx02 | a,b              |
| i1uniq     | n_diff_pfx01 | c                |
| i1uniq     | n_diff_pfx02 | c,d              |
| i2nonuniq  | n_diff_pfx01 | e                |
| i2nonuniq  | n_diff_pfx02 | e,f              |
| i2nonuniq  | n_diff_pfx03 | e,f,a            |
| i2nonuniq  | n_diff_pfx04 | e,f,a,b          |
| i3nonuniq  | n_diff_pfx01 | g                |
| i3nonuniq  | n_diff_pfx02 | g,h              |
| i3nonuniq  | n_diff_pfx03 | g,h,a            |
| i3nonuniq  | n_diff_pfx04 | g,h,a,b          |
+------------+--------------+------------------+
12 rows in set (0.01 sec)

根据上面显示的索引统计数据和表定义,可以确定以下值:
.n_cols_in_uniq_i,不计算主键列的所有唯一索引中所有列的总数为2 (c和d)

.n_cols_in_non_uniq_i,所有非唯一索引中所有列的总数,为4 (e、f、g和h)

.n_cols_in_pk,主键中的列数是2(a和b)

.n_non_uniq_i,表中非唯一索引的数量为2 (i2nonuniq和i3nonuniq))

.n_part, 分区数,为1

现在可以计算innodb_stats_persistent_sample_pages *(2 + 4 + 2 *(1 + 2)) * 1来确定扫描的叶页数。如果将innodb_stats_persistent_sample_pages设置为默认值20,并将默认的页面大小设置为16 KiB (innodb_page_size=16384),那么你可以估计为表t读取20 * 12 * 16384字节,或者大约4 MiB。

所有4MiB可能不是从磁盘读取的,因为一些叶页可能已经缓存在缓冲池中。