Magento 2 运行索引或后台报表时出现 The table is fullNo space left on device,第一反应往往是清理 var/cache。但错误如果来自 MySQL,Web 节点还有空间也没有用。MySQL 的磁盘临时文件可能写在独立 tmpdir,InnoDB 内部临时表还可能进入 ibtmp1,必须先确定满的是哪个文件系统。

先停止制造更多写入

索引、导入和大型报表仍在运行时,删除零散日志只能争取几秒。先暂停触发问题的 job 或把后台入口临时限制给管理员,保留订单等核心流量。不要在磁盘 100% 时盲目重启 MySQL,崩溃恢复同样需要空间。

df -h
df -i
mysql -e "SHOW VARIABLES LIKE 'tmpdir'; SHOW VARIABLES LIKE 'innodb_temp_data_file_path';"
mysql -e "SHOW GLOBAL STATUS LIKE 'Created_tmp%';"

df -i 能发现 inode 耗尽。Created_tmp_disk_tables 是累计值,要间隔一分钟采样增量并结合请求量判断,不能只看数字大就下结论。

哪些 Magento 查询容易落盘

商品集合同时 join 多个 EAV 属性、使用 DISTINCTGROUP BY 和大范围 ORDER BY 时,结果无法利用合适索引,容易生成临时表。价格与目录规则全量索引会处理大量 website/customer group 组合;后台销售报表按长时间段聚合;第三方导出把全部订单一次取出,也常形成大排序。

另一个信号是查询选择了 TEXT/BLOB 列。即使 tmp_table_size 很大,某些结构也会直接使用磁盘临时表。把参数无限增大不仅占内存,还可能导致并发连接同时申请大量空间。

抓住正在执行的 SQL

mysql -e 'SHOW FULL PROCESSLIST'
mysql -e "SELECT THREAD_ID, EVENT_NAME, SQL_TEXT, TIMER_WAIT
FROM performance_schema.events_statements_current
WHERE SQL_TEXT IS NOT NULLG"

生产环境应限制输出并保护其中的客户数据。若问题已经结束,查慢查询日志与 Performance Schema 历史。Magento 的异常堆栈能指出 collection 或 indexer,但真正需要优化的是生成的 SQL、访问行数与执行计划。

EXPLAIN FORMAT=JSON
SELECT /* 从慢日志复制并脱敏后的查询 */ 1;

不要对生产库直接运行来源不明的完整 SELECT,尤其是可能再次创建巨型临时表的查询。可在副本或相同数据量的测试环境分析。

观察 InnoDB 临时表空间

在兼容版本中,可查看 InnoDB 临时表相关的 information_schema/performance_schema 指标以及数据目录的 ibtmp1 大小。这个文件增长后通常不会像普通临时文件一样立即缩回操作系统。计划重启才能回收时,必须先确认复制、备份、恢复空间与维护窗口,不能把“重启会变小”当作在线修复。

从代码侧减少数据集

自定义 collection 只选择需要字段;分页导出时使用稳定的主键游标,不要用越来越大的 OFFSET;聚合报表使用预计算表;对高频过滤与关联列添加经过验证的复合索引。Magento EAV 查询里随意增加 joinAttribute 可能把一行商品扩成多行,先确认关联基数。

// 使用主键游标分批,而不是一次加载所有实体
$collection->addFieldToFilter('entity_id', ['gt' => $lastId])
    ->setOrder('entity_id', 'ASC')
    ->setPageSize(500);

循环内必须清理已加载集合和大对象,记录 lastId,并让任务可从断点继续。

数据库参数只能在证据之后调整

tmp_table_sizemax_heap_table_size 取较小值作为相关上限,但增大它们会放大每连接内存风险。tmpdir 迁移到更大磁盘也需要权限、挂载和安全策略。先用查询计划减少写入量,再按并发容量调整参数。

恢复后应记录磁盘增长曲线、触发 job、SQL 摘要、检查行数与修复前后耗时。只清空临时文件而不定位查询,下一次全量索引或月末报表仍会把磁盘写满。