MySQL 5.7 升级 8.0 FTS 索引问题:原因与解决方案
2025-01-22 13:58:46
MySQL 5.7 升级 8.0 FTS 索引问题分析与解决
在 MySQL 5.7 升级至 8.0 的过程中,有时会遇到由于 FTS (Full-Text Search,全文搜索) 索引引起的辅助表创建在系统表空间的问题,这个问题的根源在于 MySQL 的一个已知缺陷 (bug #72132)。如果不进行适当的处理,MySQL 8.0 在对此类表执行 DDL (Data Definition Language) 操作时,可能导致数据库不可用。这要求我们在升级前,采取适当的预防措施。
问题现象
错误报告通常包含如下,表明相关表的 FTS 索引的辅助表位于系统表空间。此类问题可能影响任何带有 FULLTEXT
索引的表,在多租户环境下尤其常见。错误消息示例:
{
"level": "Error",
"dbObject": "@[email protected]",
"description": " The auxiliary tables of FTS indexes on the table '@[email protected]' are created in system table-space due to https://bugs.mysql.com/bug.php?id=72132. In MySQL8.0, DDL queries executed on this table shall cause database unavailability. To avoid that, drop and recreate all the FTS indexes on the table or rebuild the table using ALTER TABLE query before the upgrade."
}
并且,在尝试升级之后,可能会遇到类似的错误:
{
"id": "auroraGetDanglingFulltextIndex",
"title": "Tables with dangling FULLTEXT index reference",
"status": "ERROR",
"description": "Table '@007bb281b00a-14bb-4097-aa29-e9432f2e55db@007d.#sql-ib32025827-3477973988' doesn't exist"
}
#sql-ibxxx
的表表明与某个删除的表仍然存在残留,属于 InnoDB
内部的临时表。
问题原因
此问题源于 MySQL 5.7 中,FTS 索引辅助表存储位置的不当,当辅助表被错误地创建在了系统表空间中。在升级到 8.0 后,MySQL 对于表空间的管理更为严格,使得对此类表进行修改或重建时引发错误。在未事先进行处理的情况下,ALTER TABLE
语句会尝试更新存储在系统表空间的 FTS 辅助表,而该表不存在或位于非预期的位置,导致升级失败。
解决方案
1. 移除并重建 FTS 索引
这种方式,会彻底移除有问题的 FULLTEXT
索引,通过ALTER TABLE
命令重建数据表并确保该表与 InnoDB
表空间相关联,然后再重新添加全文索引。这样可以避免与错误位置的辅助表产生冲突。
操作步骤
-
识别带有 FTS 索引的表 : 使用
SHOW INDEX
语句查询表上的FULLTEXT
索引。SHOW INDEX FROM 表名;
查看结果,找出
Key_name
列中值为索引名称,Index_type
列的值为FULLTEXT
的索引。 -
删除
FULLTEXT
索引 : 如果存在,使用ALTER TABLE
删除。ALTER TABLE 表名 DROP INDEX 索引名;
-
重建表 : 使用
ALTER TABLE
修改表引擎,使其正确关联InnoDB
表空间。
ALTER TABLE 表名 ENGINE = InnoDB;
-
优化表 : 运行
OPTIMIZE TABLE
重建表并确保表内部数据布局的一致性,包括辅助索引。OPTIMIZE TABLE 表名;
-
重建
FULLTEXT
索引 :使用ALTER TABLE
添加先前移除的FULLTEXT
索引。ALTER TABLE 表名 ADD FULLTEXT INDEX 索引名 (列1, 列2, ...);
注意: OPTIMIZE TABLE
可能在大型表上运行时间较长,可根据表的大小,选择在业务低峰时段执行。
2. 使用 ALTER TABLE
直接重建表
当确认所有的FULLTEXT
索引的错误都被清除以后,并且残留的 #sql-ibxxx
临时表无法删除时。使用 ALTER TABLE 表名 ENGINE=InnoDB FORCE;
命令可以强制重建表。 此命令确保数据表引擎设置为 InnoDB, 以及 InnoDB
相关表空间的使用。该操作具有类似效果, 将原始表空间相关的旧表信息置于正常状态,使它可被后续 DDL
操作处理。
这个操作和重新构建FULLTEXT
索引在操作上存在部分重叠。但好处是可以一次解决,并减少步骤。
ALTER TABLE 表名 ENGINE=InnoDB FORCE;
完成之后可再执行:
OPTIMIZE TABLE 表名;
确保所有相关的 FTS 索引都已重建,并在表元数据中正确关联表空间信息。
代码示例 (使用 Laravel Job)
以下的 PHP 代码展示了如何在 Laravel Job 中实现此操作。
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
class FixAuxBugForInnoDBFTSIndexesJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $database;
public function __construct($database)
{
$this->database = $database;
}
public function handle()
{
try {
config([
'database.connections.auto_master.database' => $this->database,
]);
DB::purge('auto_master');
retry(
5,
function () {
DB::reconnect('auto_master');
},
100
);
$this->fixTable('customers');
$this->fixTable('lineitems');
} catch (\Throwable $th) {
throw $th; // 处理或记录错误。
}
}
private function fixTable($tableName)
{
$tableExists = Schema::connection('auto_master')->hasTable($tableName);
if ($tableExists)
{
// 1. 查找FTS索引。
$indexes = DB::select('SHOW INDEX FROM ' . $tableName);
// 2. 找到FULLTEXT类型的索引
$fulltextIndexes = array_filter($indexes, function($index)
{
return $index->Index_type == 'FULLTEXT';
});
foreach($fulltextIndexes as $index) {
//3. 删除找到的FTS索引
Schema::connection('auto_master')->table($tableName,function (Blueprint $table) use ($index)
{
$table->dropIndex($index->Key_name);
});
}
// 4. 使用 ALTER TABLE ... FORCE 重建表。
DB::connection('auto_master')->statement('ALTER TABLE '. $tableName. ' ENGINE=InnoDB FORCE;');
//5. 优化表
DB::connection('auto_master')->statement('OPTIMIZE TABLE '. $tableName .';');
}
}
}
此示例代码会自动遍历指定数据库中的customers
和lineitems
表,删除它们的 FULLTEXT
索引,重建表引擎,然后重新建立 FULLTEXT
索引。您可以在生产环境中调整,使其适用于各种带有FULLTEXT
索引的表。
安全建议
- 在执行操作前务必备份数据库,尤其是在生产环境中,防止发生意外。
- 在测试环境中验证这些方法,确保它们符合预期,不会造成数据丢失或其他不良影响。
- 执行时需要有充足的等待时间,对于大型数据库和表,这个过程可能会耗时较久。
升级数据库是一个严谨的过程,确保所有可能的隐患都被排除可以帮助顺利过渡。 以上处理方法提供一种处理 FTS
索引相关问题的思路,请根据自己的实际情况做出调整和应对。