已采纳
回答正文
回复
讨论正文
该问题的正文、回答与讨论。
我负责一套订单履约系统的 MySQL 8.0.32(单主 16C64G,innodb_buffer_pool_size=48G),核心表 t_order_item 约 6 亿行、8 个二级索引,数据文件初始 780GB。每天凌晨归档任务 DELETE 约 8% 的行(WHERE created_at < NOW() - INTERVAL 180 DAY AND status IN ('DELIVERED','CANCELLED')),单事务拆成 20 万行一批提交。
SHOW TABLE STATUS WHERE Name='t_order_item' → Data_free = 2516582400(约 2.4GB),初始为 0;SELECT FILE_SIZE, DATA_SIZE FROM information_schema.INNODB_SYS_TABLESPACES WHERE NAME='t_order_item' → FILE_SIZE 从初始 836GB 涨到 892GB,只增不减;du 看到的 .ibd 文件大小确实在涨;idx_order_no,但 rows 从 3 涨到 11,filtered 从 100% 降到 72%;SHOW ENGINE INNODB STATUS 的 BUFFER POOL 段:Free buffer pool pages 约 42 万页(≈6.4GB),没有明显减少;INNODB_SYS_TABLES.N_ROWS 从 6.21 亿降到 5.72 亿(-7.9%),但 DATA_SIZE 从 780GB 涨到 892GB。ANALYZE TABLE t_order_item 后重新 EXPLAIN → 仍走 idx_order_no,rows 不变;pt-duplicate-key-checker → 无重复索引;information_schema.INNODB_BUFFER_PAGE 前 200 行 → PAGE_STATE 全部 FILE_PAGE,PAGE_TYPE 中 INDEX 占 83%、UNDO_LOG 占 9%、TRANSACTION 占 8%,分布正常;INNODB_SYS_INDEXES 各索引的 STATS 字段 → 二级索引 STATS(约等于叶子页数)总和从 2.1 亿页涨到 2.4 亿页(+14%),主键索引叶子页从 1.8 亿降到 1.67 亿(-7%),但二级索引没降;SHOW VARIABLES LIKE 'innodb_autoinc%' → 无关;ALTER TABLE t_order_item ENGINE=InnoDB, ALGORITHM=COPY(在测试库 1 亿行副本上)→ 耗时 4h12min,期间原表仍可读写但锁等待 30s+;生产 6 亿行估算要 25h+。autoextend(默认 128MB 步进)导致文件只能变大不能缩小?还是说 Data_free 的 2.4GB 空间其实已经在 .ibd 文件内部"标记为空闲"、但 OS 层根本没 truncate?Data_free 的 2.4GB 和 FILE_SIZE - DATA_SIZE 的差值(约 12GB)到底是什么关系?我算出来 FILE_SIZE - DATA_SIZE = 12GB,但 Data_free 只有 2.4GB,剩下的 ~9.6GB 去哪了?是二级索引膨胀占的?innodb_file_purge_delay 不存在(那是 5.7 的 innodb_purge_batch_size 相关),有没有类似 innodb_space_reclaim_interval 的参数?还是说 InnoDB 的设计就是"只增不减,想缩就 OPTIMIZE"?ALGORITHM=COPY(测试库 4h+),ALGORITHM=INPLACE 对 OPTIMIZE TABLE 是否有效(文档说 InnoDB 的 OPTIMIZE 走 INPLACE,但实际是不是还是 COPY?)?有没有 pt-online-schema-change 或 gh-ost 这类工具更适合的场景?FILE_SIZE、DATA_SIZE、Data_free 三者的精确关系和各自对应的 InnoDB 内部结构(FSP 空闲链表 vs 二级索引叶子页);社区已有两篇相关问题但角度不同: