我在生产实例中遇到了这个问题,因此尝试了小规模的本地重新创建并成功完成。
我有一个简单的测试表
CREATE TABLE `test` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`val` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `index2` (`val`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
我正在使用8.0.26
带有innodb
存储引擎的Mysql 版本
我在这个表中填充了大约 400 万行随机数据。从这个表中选择 5000 行大约需要 50 毫秒。然后我使用DELETE FROM test;
删除所有行后,如果我再运行SELECT * FROM test LIMIT 5000;
此查询,则需要 1 分钟以上才能运行。当选择查询最终完成运行时,它返回 0 行(如预期的那样)。
在继续之前,我只想澄清一下,我知道运行optimize table
将修复该问题,但我有兴趣了解幕后到底发生了什么。以下是我的一些想法
- 大约一小时后,查询再次变为即时查询。这让我相信某种垃圾收集或清理正在幕后进行。但我在文档中找不到有关此内容的任何信息。
- 删除后,查询速度明显变慢。由于我在选择查询中未使用任何未索引子句,因此在删除前大约需要 50 毫秒才能解决,因此删除后速度会慢 1500 倍。
- 我研究过“幽灵记录”的概念,但是我能找到的所有结果都只涉及 SQL Server,而不是 Mysql,这让我相信“幽灵记录”的概念可能不存在于 Mysql 中。我在 Mysql 文档中找不到关于此内容的任何提及。
我尝试了慢查询日志,希望能看到一堆扫描的数据,即使它已被删除(幽灵记录),但除了持续时间之外,我看不到任何奇怪或意外的东西
# Time: 2025-02-11T10:29:24.510606Z
# User@Host: root[root] @ [172.17.0.1] Id: 20978
# Query_time: 69.680895 Lock_time: 0.000135 Rows_sent: 0 Rows_examined: 0 Thread_id: 20978 Errno: 0 Killed: 0 Bytes_received: 0 Bytes_sent: 130 Read_first: 1 Read_last: 0 Read_key: 1 Read_next: 0 Read_prev: 0 Read_rnd: 0 Read_rnd_next: 0 Sort_merge_passes: 0 Sort_range_count: 0 Sort_rows: 0 Sort_scan_count: 0 Created_tmp_disk_tables: 0 Created_tmp_tables: 0 Start: 2025-02-11T10:28:14.829711Z End: 2025-02-11T10:29:24.510606Z
SET timestamp=1739269694;
select * from test
LIMIT 0, 5000;
有人能详细解释一下这里到底发生了什么吗?理想情况下,如果可能的话,我想知道的两件事是:
- 到底发生了什么事?
- 是否可以通过查看一些内部 Mysql 统计数据来查看/诊断此问题?例如,innodb 引擎状态/information_schema/performance_schema。基本上,我可以查看并判断某个表是否存在此问题,而无需知道刚刚运行了删除操作
以下是选择的解释 -SELECT * FROM test LIMIT 5000
删除前(快速 50 毫秒)
id, select_type, table, partitions, type, possible_keys, key, key_len, ref, rows, filtered, Extra
'1', 'SIMPLE', 'test', NULL, 'index', NULL, 'index2', '1022', NULL, '6958223', '100.00', 'Using index'
删除后(慢 69 秒) - 我运行analyze table test
更新统计信息,然后重新运行选择并解释
id, select_type, table, partitions, type, possible_keys, key, key_len, ref, rows, filtered, Extra
'1', 'SIMPLE', 'test', NULL, 'index', NULL, 'index2', '1022', NULL, '1', '100.00', 'Using index'