• mysql_alter_table函数流程的部分修改和注解


    change log

    2020-06-03: 补充 https://dev.mysql.com/doc/refman/5.6/en/innodb-online-ddl-operations.html,补充测试算法语句

    gdb info

    set args --defaults-file=etc/my.cnf --user=liuzhuan
    
    调试的断点列表
    mysql_alter_table()
    
    create_table_info_t::innobase_table_flags()
    
    修改发生位置
    ./sql/mysqld.cc: //[liuzhuan] 增加一个全局hash存储算法项
    
    ./plugin/daemon_example/daemon_example.cc: //[liuzhuan] 改写为mysql_pthread(sep-15 second)静默方式刷盘算法数据
    
    ./storage/innobase/handler/ha_innodb.cc: //[liuzhuan] 改写为向hash存储算法项,key是table name(排除临时表),value是算法
    
    ./storage/innobase/os/os0file.cc://[liuzhuan] os0file刷盘page位置增加了算法分支,分支的入参是IORequest这个类,算法的判断依据来自hash内存储的key
    
    ./storage/innobase/include/os0file.h //[liuzhuan] 修改了IORequest这个类,增加了算法判断的一个表达式,这样的考虑个人认为是比较妥当的,因为堆栈函数的入参不用去改了
    

    mysql5.6以后内部在alter table上有两种算法,做如下定义

    ALGORITHM=INPLACE
    ALGORITHM=COPY
    
    copy table方式
      新建跟原表格一致的临时表,并在该临时表上执行DDL语句
      锁原表,不允许DML,允许查询
      逐行数据从原表拷贝到临时表中(这个过程是没有排序的)
      拷贝结束后,原表禁止读操作,也就是原表此时不提供读写服务
      进行rename操作,完成DDL过程
    
    inplace方式(fast index creation,仅针对索引的创建跟删除)
      新建frm临时文件
      锁原表,不允许DML,允许查询
      按照聚集索引的顺序,查询数据,找到需要的索引列数据,排序后插入到新的索引页中
      原表禁止读操作,也就是原表此时不提供读写服务
      进行rename操作,替换frm文件,完成DDL过程
    

    这两种算法的IO行为区别很大,具体在这里不再表述,引用一个博主的文章,对online ddl解释的非常漂亮了:

    [苏家小萝卜][https://www.cnblogs.com/xinysu/p/6732646.html]
    Online DDL实现原理

    SQL语句默认的算法行为

    inplace算法
      alter table encrypt_test_1 ENCRYPTION='y';
      alter table encrypt_test_1 add passtest int(4) default 0, ADD genedetail varchar(50) default '0', encryption='y';
    
      CREATE TABLE `test_5` (
        `id` int(11) DEFAULT NULL,
        `name` varchar(32) DEFAULT NULL,
        `passtest` int(4) DEFAULT '0',
        `genedetail` varchar(50) DEFAULT '0'
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ENCRYPTION='n';
    
      CREATE INDEX idd1 ON test_5 (`id`);
      ALTER TABLE test_5 ADD INDEX nameid1 (name);
    
      DROP INDEX idd1 ON test_5;
      ALTER TABLE test_5 DROP INDEX nameid1;
    
      CREATE FULLTEXT INDEX nameid1 ON test_5(name);
      DROP INDEX nameid1 ON test_5;
    
      ALTER TABLE test_5 ADD CONSTRAINT fk_name1 FOREIGN KEY(id) REFERENCES t1(id);
    
    copy算法
      CREATE TEMPORARY TABLE aaa as ( select * from encrypt_test_1);
      CREATE TABLE aaa as ( select * from encrypt_test_1);
      alter table encrypt_test_1 ENCRYPTION='n';
    

    mysql 5.7后版本中的一个bug

    CREATE TABLE `test_5` (
      `id` int(11) DEFAULT NULL,
      `name` varchar(32) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 encryption='y';
    
    然后取消encryption,设置alter table test_5 encryption='n';
    
    最后执行alter table test_5 ENGINE=myisam会出错,这里在
    ./storage/myisam/ha_myisam.cc中ha_myisam::create()存在一处bug
    
    2024 if (ha_create_info->encrypt_type.length > 0)
    2025│   {
    2026│     set_my_errno(HA_WRONG_CREATE_OPTION);
    2027│     DBUG_RETURN(HA_WRONG_CREATE_OPTION);
    2028│   }
    
    这个条件是不可能失败的,这样的结果就是encrypt后的innodb表,转myisam都会失败,这在mariadb中是通过table comment解决的,他把这种变革前的语句写到了comment里,想法也说不上多好
    但也算个解决方法吧
    
    他也间接导致sql_table.cc-->mysql_alter_table()函数的copy模式下:
    9871行
    if (ha_create_table())
      goto err_new_table_cleanup; //成立
    从而返回 ERROR 1031 (HY000): Table storage engine for '#sql-1ba8_2' doesn't have this option
    

    根据上述两种算法,在alter table中找到算法发生位置,一共要修改三处

    bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name, HA_CREATE_INFO *create_info, ABLE_LIST *table_list, Alter_info *alter_info){
      1:
      9230行,if (alter_ctx.is_table_renamed()) 他是alter table ... reanme ... 词法的切入点,这里直接发生调用mysql_rename_table,然后根据执行状态返回true(失败)或false(成功)
      if (table->s->tmp_table != NO_TMP_TABLE) 判断是否具备临时表,table->s->tmp_table有定义好的几种类型在table.h中定义
      引用table.h中定义
      enum tmp_table_type
      {
        NO_TMP_TABLE, NON_TRANSACTIONAL_TMP_TABLE, TRANSACTIONAL_TMP_TABLE, INTERNAL_TMP_TABLE, SYSTEM_TMP_TABLE
      };
      INTERNAL_TMP_TABLE :      大致如'#sql-5bf6',内部临时表后是一个动态数,每次mysql重启,这个动态数都会更新
      TRANSACTIONAL_TMP_TABLE : 更多发生在inplace模式,事务性临时表
      这个位置修改alter rename对hash的操作
      
      2:
      9733行, switch (inplace_supported) 这里进入inplace模式的处理,这种情况下,if (use_inplace)条件成立
      这个位置处理无table io的流程(inplace无io,这里切换hash算法是不能被支持的)
      
      3:
      9822行,if (!table->s->tmp_table) 这里进去表拷贝模式
      这个位置处理copy io流程下,表的encrypt关键字变更
    }
    
  • 相关阅读:
    mongodb 的安装历程
    从C的声明符到Objective-C的Blocks语法
    #译# Core Data概述 (转)
    避免在block中循环引用(Retain Cycle in Block)
    GCD和信号量
    Blocks的申明调用与Queue当做锁的用法
    [译]在IB中实现自动布局
    清理Xcode的技巧和方法
    SVN的Status字段含义
    iOS应用崩溃日志揭秘2
  • 原文地址:https://www.cnblogs.com/liuzhuan23/p/13032960.html
Copyright © 2020-2023  润新知