单条记录大小增长倍数和ibd文件大小的增长倍数不成正比

单条记录大小增长倍数和ibd文件大小的增长倍数不成正比

环境信息

数据库版本: GreatSQL 8.0.25

字符集:utf8mb4

innodb_default_row_format: dynamic

innodb_page_size: 16384

问题描述

表数据为新insert数据,无delete、无update

GreatSQL 一个数据量为1万的A表,有100个varchar字段,每个字段存10字节,ibd大小为21M

GreatSQL 一个数据量为1万的B表,有100个varchar字段,每个字段存100字节,ibd大小为4.7G

问题:相同数据量,相同数据量,B表的每行比A表大10倍,磁盘使用大小不是10倍,而是200多倍?

greatsql> show create table t_user_100_1000_100  \G;
*************************** 1. row ***************************
       Table: t_user_100_1000_100
Create Table: CREATE TABLE `t_user_100_1000_100` (
  `id` int NOT NULL AUTO_INCREMENT,
  `c_name1` varchar(10) NOT NULL DEFAULT '',
。。。
  `c_name100` varchar(10) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

greatsql> show create table t_user_100_10000_100  \G;
*************************** 1. row ***************************
       Table: t_user_100_10000_100
Create Table: CREATE TABLE `t_user_100_10000_100` (
  `id` int NOT NULL AUTO_INCREMENT,
  `c_name1` varchar(100) NOT NULL DEFAULT '',
。。。
  `c_name100` varchar(100) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

greatsql> select count() from t_user_100_10000_100 ;
+----------+
| count() |
+----------+
| 10000 |
+----------+
1 row in set (0.06 sec)

greatsql> select count() from t_user_100_1000_100 ;
+----------+
| count() |
+----------+
| 10000 |
+----------+
1 row in set (0.18 sec)

#os ibd 文件大小
ll
total 4313096
-rw-r----- 1 mysql mysql 5016387584 Apr 9 18:52 t_user_100_10000_100.ibd
-rw-r----- 1 mysql mysql 20971520 Apr 9 18:40 t_user_100_1000_100.ibd

greatsql> select 5016387584/20971520 from dual;
+---------------------+
| 5016387584/20971520 |
+---------------------+
| 239.2000 |
+---------------------+
1 row in set (0.00 sec)

问题分析

多出来的24倍难道是碎片导致的?

使用optimize table重整表后,几乎没有任何优化,查看系统视图,也没有多少空洞。

file

使用官方工具innochecksum查看表空间文件PAGE类型分布,可以看到,B表相对A表多了大量的Other type of page。看来主要的空间消耗是在这个“Other”上。

file

  • INNODB的行溢出

INNODB默认下每个PAGE的大小为16K。B表每行10K,每个PAGE只能存放1行记录,余下的6K就浪费了。但即使按照这个算法,也只浪费了37%的空间。

实际上,INNODB在这里有个处理,当记录过大,会将最大的列使用一个指针替代,指针指向一个新的PAGE,在该PAGE上存放实际数据。

由函数page_zip_rec_needs_ext()判断是否需要溢出。判断方式是该记录长度是否大于空PAGE的可用空间。

file

GDB执行一下,可以看到一个16k的PAGE实际可用的空间为16252字节(页头等占用了小量字节)。一半粗略算作是8k。

file

如果行长度大于8K,会将最长的列存放到新的PAGE,原位置使用20字节的指针代替。如果处理后,行长度依然大于8K,则选择当前最长的列进一步处理,不断循环。如果列长度无法进一步缩少,仍然大于8K,则抛出DB_TOO_BIG_RECORD错误,即“row size too large”。dtuple_convert_big_rec()函数上可以看到更多的执行细节。

file

  • 小量数据溢出的情况

以下堆栈展示把溢出数据写入"Off Page"。主要函数为lob::insert()。

file

log::insert()会申请一个新的16K大小的PAGE,并将数据写入新的page。

dberr_t insert(){
  ......
  //分配一个新的16KB的PAGE
  first_page_t first(mtr, index);
  buf_block_t *first_block = first.alloc(mtr, ctx->is_bulk());
  ......
  //将100字节写入写入
  ulint to_write = first.write(trxid, ptr, len);
  ......
 }

以下是B表插入数据,往innodb"Off page"写入数据时候的断点,可以看到只写了B表单列100字节数据。16KB的容量只写100字节的数据,剩余99%的空间用不上,实在太浪费了。

file

B表有100个varchar列,每个列100字节。如果需要满足列长少于8K,需要25个列以上进行溢出(一个列还有隐藏列和其它数据,实际需要溢出的列略多于25)。使用innochecksum查询到“OTHER” page 有29万,B表有一万行,平均每行29个“OTHER” page。看来这个“OTHER” page基本都是这种“Off page”了。

问题总结

GreatSQL 白白浪费了95%的磁盘空间,是因为大量的列溢出了小量的数据。INNODB存放每个溢出列的数据的最小分配单元大小是16KB。原本10KB的行长度,需要多占N倍的存储空间。

优化建议

表设计时,要注意控制行长度小于8k,避免小量列数据溢出,导致磁盘容量和性能问题。

延伸阅读


Enjoy GreatSQL :)

关于 GreatSQL

GreatSQL是适用于金融级应用的国内自主开源数据库,具备高性能、高可靠、高易用性、高安全等多个核心特性,可以作为MySQL或Percona Server的可选替换,用于线上生产环境,且完全免费并兼容MySQL或Percona Server。

相关链接: GreatSQL社区 Gitee GitHub Bilibili

GreatSQL社区:

image

社区有奖建议反馈: https://greatsql.cn/thread-54-1-1.html

社区博客有奖征稿详情: https://greatsql.cn/thread-100-1-1.html

(对文章有疑问或者有独到见解都可以去社区官网提出或分享哦~)

技术交流群:

微信&QQ群:

QQ群:533341697

微信群:添加GreatSQL社区助手(微信号:wanlidbc )好友,待社区助手拉您进群。

<think>好的,我现在需要帮助用户解决如何在Navicat中配置MySQL数据库文件的初始大小、增量增长设置。用户提到要将初始文件大小设为5MB,增量2MB,并且限制增长。根据之前的对话,用户可能是在参考SQL Server的配置方式,但需要转换到MySQL的环境下。 首先,我需要回顾MySQL的文件管理机制。根据之前的回答,MySQL的InnoDB引擎使用表空间来管理数据,像SQL Server有独立的.mdf.ldf文件。因此,用户提到的“文件”可能是指表空间文件。InnoDB默认使用共享表空间(ibdata1)或者独立表空间(每个表的.ibd文件)。过,用户可能希望调整整个数据库的存储设置,而仅仅是单个表。 接下来,用户的需求包括初始大小5MB,增量2MB,限制增长。在MySQL中,全局表空间的初始大小由innodb_data_file_path参数控制。例如,ibdata1:12M:autoextend。这里的12M是初始大小,autoextend允许自动扩展,每次扩展的大小由innodb_autoextend_increment参数决定,默认为64MB。但用户希望增量是2MB,这需要调整这个参数。 所以,用户需要修改my.cnf或my.ini配置文件中的innodb_autoextend_increment为2MB。同时,设置innodb_data_file_path来指定初始大小过,通常建议将全局表空间设置得太小,因为这可能导致频繁扩展,影响性能。因此,可能需要建议用户考虑使用独立表空间(innodb_file_per_table=ON),这样每个表有自己的.ibd文件,可能更容易管理。 此外,用户使用Navicat进行操作,可能需要指导如何在Navicat中修改这些配置。但Navicat本身提供图形界面来直接修改这些参数,需要通过编辑配置文件并重启MySQL服务。因此,步骤可能包括:通过Navicat的“工具”菜单打开命令列界面,执行SHOW VARIABLES命令来确认当前设置,然后引导用户手动修改配置文件,并重启服务。 还需要注意,修改innodb_data_file_path时,如果之前已经存在表空间文件,可能需要先删除或迁移数据,这可能会导致数据丢失,因此建议在测试环境中操作,并提醒用户备份数据。 另外,用户提到“限制增长”,在MySQL中,表空间默认是自动扩展的,除非磁盘空间足,所以需要额外设置。但需要确保innodb_autoextend_increment调整到2MB,以满足增量需求。 可能还需要解释为什么MySQL没有像SQL Server那样直接的文件配置选项,因为两者的架构同。同时,提醒用户频繁的小增量扩展可能会影响性能,建议权衡利弊。 最后,验证步骤包括通过SQL命令检查参数是否生效,如SHOW VARIABLES LIKE 'innodb_autoextend_increment'; 检查表空间文件的大小变化。 总结步骤:修改配置文件中的相关参数,重启MySQL服务,验证配置是否生效,并考虑使用独立表空间以便更灵活管理。</think>根据MySQL的存储机制Navicat操作特点,以下是配置数据库文件参数的完整方案: ### 一、MySQL表空间核心配置原理 1. **InnoDB引擎架构**:通过`innodb_data_file_path`参数控制全局表空间文件 2. **自动扩展机制**:由`innodb_autoextend_increment`参数控制扩展步长(默认64MB) 3. **独立表空间模式**(推荐):通过`innodb_file_per_table=ON`实现每个表单独存储[^1] ### 二、Navicat配置操作步骤 #### 步骤1:修改MySQL配置文件 1. 通过Navicat菜单栏进入`工具 → 命令列界面` 2. 执行命令定位配置文件路径: ```sql SHOW VARIABLES LIKE 'config_file'; ``` 3. 修改`my.ini`/`my.cnf`文件: ```ini [mysqld] # 全局表空间配置 innodb_data_file_path = ibdata1:5M:autoextend:maxsize=unlimited innodb_autoextend_increment = 2 innodb_file_per_table = ON ``` #### 步骤2:应用新配置 1. 重启MySQL服务(通过Navicat右键点击连接选择`重启服务`) 2. 验证参数生效: ```sql SHOW VARIABLES LIKE 'innodb_autoextend_increment'; -- 应显示2(单位MB) SHOW VARIABLES LIKE 'innodb_data_file_path'; -- 应显示5M配置 ``` #### 步骤3:创建测试数据库 1. 右键新建数据库`BookStore` 2. 指定字符集为`utf8mb4` 3. 创建测试表验证独立表空间: ```sql CREATE TABLE books ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255) ) ENGINE=InnoDB; ``` ### 三、文件存储结构验证 ``` D:\DBF ├── ibdata1 # 初始5MB,按2MB增量扩展 ├── ib_logfile0 # 重做日志 ├── ib_logfile1 └── BookStore └── books.ibd # 独立表空间文件(动态增长) ``` ### 四、配置对照表 | 需求参数 | MySQL实现方式 | 配置示例 | |-----------------|-------------------------------|---------------------------| | 初始文件大小 | `innodb_data_file_path` | `ibdata1:5M:autoextend` | | 文件增量 | `innodb_autoextend_increment` | `2`(单位MB) | | 限制增长 | `maxsize=unlimited` | 默认限制 | ### 五、高级配置建议 1. **独立表空间管理**(推荐): ```ini innodb_file_per_table = ON innodb_flush_method = O_DIRECT ``` 2. **文件增长监控**: ```sql SELECT FILE_NAME, TABLESPACE_NAME, ROUND((DATA_FREE / 1024 / 1024), 2) AS free_space_MB FROM information_schema.FILES WHERE ENGINE = 'InnoDB'; ``` ### 六、注意事项 1. 修改`innodb_data_file_path`需先删除原`ibdata*`文件(数据会丢失) 2. 建议在数据库初始化前配置存储参数 3. 实际磁盘空间消耗 = 初始值 + n×增量值 + 事务日志空间[^1] 4. 生产环境建议设置过小的增量值(可能产生磁盘碎片) --相关问题-- 1. 如何监控InnoDB表空间的实际使用情况? 2. 为什么MySQL默认使用共享表空间模式? 3. 修改`innodb_autoextend_increment`需要哪些前置条件? 4. 如何安全迁移现有的共享表空间到独立表空间? [^1]: MySQL 8.0 Reference Manual - InnoDB Configuration
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值