当前位置: 首页 > article >正文

mysql-analyze table导致waiting for table flush

一、背景

一次普通的analyze table操作却锁住了后续的查询

mysql> select sleep(100) from a;

analyze table a;

mysql> select * from a;


# 遇到这种情况就需要查询阻塞的sql,然后kill掉,或者也可以等待
68050436 | test          | 2025-02-26 11:52:40 | select sleep(100) from a

二、源码分析

这是percona解决这个问题所涉及的改动,增加了一个skip_flush 的布尔常量

@@ -906,6 +906,9 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
    }
    if (table->table)
    {

+      const bool skip_flush=
+        (operator_func == &handler::ha_analyze)
+        && (table->table->file->ha_table_flags() & HA_ONLINE_ANALYZE);
      if (table->table->s->tmp_table)
      {
        /* 
@@ -915,7 +918,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
- 原逻辑:只要需要修改表或发生致命错误,就移除表缓存
- 新逻辑:当且仅当(不需要跳过刷新 且 需要修改表)或发生致命错误时,才移除表缓存
- 保留了致命错误时的强制刷新逻辑
 */
        if (open_for_modify && !open_error)
          table->table->file->info(HA_STATUS_CONST);
      }
-      else if (open_for_modify || fatal_error)
+      else if ((!skip_flush && open_for_modify) || fatal_error)
      {
        tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
                         table->db, table->table_name, FALSE);

下面是当前的完整代码

// 当表对象存在时
if (table->table)  
{
    // 判断是否需要跳过缓存刷新(在线分析且引擎支持在线分析时跳过)
    const bool skip_flush = 
        (operator_func == &handler::ha_analyze) &&
        (table->table->file->ha_table_flags() & HA_ONLINE_ANALYZE);

    // 处理临时表逻辑
    if (table->table->s->tmp_table) 
    {
        /*
          如果表未成功打开,则不尝试获取状态信息
          (修复Bug#47633)
        */
        if (open_for_modify && !open_error)
            table->table->file->info(HA_STATUS_CONST); // 获取存储引擎状态信息
    }
    // 非临时表且满足以下条件时
    else if ((!skip_flush && open_for_modify) || fatal_error) 
    {
        // 从表定义缓存中移除该表(非强制模式)
        tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
                        table->db, table->table_name, FALSE);
        
        /*
          可能有修改操作发生,因此需要
          使查询缓存失效
        */
        table->table = 0;                        // 重置表指针(用于查询缓存失效)
        query_cache.invalidate(thd, table, FALSE); // 使该表的查询缓存失效
    }
    else 
    {
        /*
          当执行 ALTER TABLE 的分区管理操作时
          (如 ANALYZE/CHECK PARTITION)
          重置需要处理的分区状态
        */
        if (table->table->part_info &&
            lex->alter_info.flags & Alter_info::ALTER_ADMIN_PARTITION) 
        {
            set_all_part_state(table->table->part_info, PART_NORMAL); // 将所有分区状态设为正常
        }
    }
}

/* 错误处理路径:管理命令执行失败时 */
if (thd->transaction_rollback_request) 
{
    /*
      罕见情况:存储引擎请求事务回滚
      (例如发生死锁时),执行回滚操作
    */
    if (trans_rollback_stmt(thd) || trans_rollback_implicit(thd))
        goto err; // 跳转到错误处理
}
else 
{
    // 正常提交事务
    if (trans_commit_stmt(thd) || trans_commit_implicit(thd))
        goto err; // 提交失败则跳转错误处理
}

// 关闭线程相关的表对象
close_thread_tables(thd);  
// 释放事务相关的元数据锁
thd->mdl_context.release_transactional_locks();

三、percona解释

发生这种情况的原因是,在修复之前, ANALYZE TABLE 的 工作方式如下:

  1. 打开表统计信息:允许并发 DML 操作(INSERT / UPDATE / DELETE / SELECT )
  2. 更新表统计信息:允许并发 DML 操作
  3. 更新完成
  4. 使表定义缓存中的表条目无效:禁止并发 DML 操作
    4.1. 这里发生的事情是ANALYZE TABLE 将当前打开的表共享实例标记为无效。这不会影响正在运行的查询:它们将照常完成。但所有传入查询都将无法启动,直到它们可以重新打开表共享实例。并且这在所有当前正在运行的查询完成之前不会发生。
  5. 使查询缓存无效:禁止并发 DML 操作

最后两个操作通常很快,但如果另一个查询触及表共享实例或获取查询缓存互斥锁,则它们无法完成。反过来,它也无法允许传入查询启动。

但是ANALYZE TABLE 修改的是表统计信息,而不是表定义!实际上,它不会以任何方式影响已经运行的查询。如果查询在ANALYZE TABLE 完成更新统计信息之前启动,则它使用旧统计信息。ANALYZE TABLE不会影响表中的数据。因此,查询缓存中的旧条目仍然是正确的 。它没有更改表的定义。因此,无需将其从表定义缓存中删除。因此,我们避免了上面的操作 4 和 5。

对lp:1704195的修复(迁移至PS-2503)删除了这些额外的更新以及它们所需的锁,并使ANALYZE TABLE 始终能够在繁忙的生产环境中安全运行。

参考文章
八怪大佬的文章
percona解决的版本
mysql官方bug记录地址
percona解决的详细信息
percona解决的版本


http://www.kler.cn/a/564069.html

相关文章:

  • python 剪切音频
  • Python入门教程丨3.7 数据可视化
  • 代码审计入门学习
  • MySQL保存超字段长度信息时如何正确截取
  • 神卓 S500 异地组网设备实现监控视频异地组网的详细步骤
  • Redis集群化方案对比:Codis、Twemproxy、Redis Cluster
  • 介绍一下在自动驾驶 路径规划和 控制算法 详细一些
  • java对hdfs文件的拉取和上传操作
  • Unity制作游戏项目——Unity项目如何导出安装包(Inno Setup Compiler的使用)——附有Inno Setup Compiler软件安装包
  • (十)趣学设计模式 之 外观模式!
  • Android移动应用开发实践-1-下载安装和简单使用Android Studio 3.5.2版本(频频出错)
  • JAR可以发布到Maven中央仓库吗?详细操作流程
  • 微软推出Office免费版,限制诸多,只能编辑不能保存到本地
  • DP学习第七篇之最小路径和
  • Rk3568驱动开发_驱动编写和挂载_2
  • 1.介绍一下TCP/IP模型和OSI模型的区别【中高频】
  • 每天五分钟深度学习pytorch:使用Inception模块搭建GoogLeNet模型
  • Word表格中如何只单独调整某一单元格宽度
  • 利用OCR识别技术,可快速实现集装箱号码识别
  • Prompt CO-STAR 框架的用用