@@ -755,8 +755,7 @@ <h1 class="post-title" itemprop="name headline">
755
755
756
756
757
757
758
-
759
- < h3 id ="背景 "> < a href ="#背景 " class ="headerlink " title ="背景 "> </ a > 背景</ h3 > < p > 因为业务的需求, 公司的一张大表需要添加字段, 先看了下表的大小, 行数到是还行, 才几十万, 但是, 因为有大字段的原因, 这个表有几十个G, 因此, 考验的时候就来了, 找了个业务不繁忙的时候, 果断添加了字段, 可是这个过程中, ddl执行了快一个半小时, 然后磁盘的iops快要爆炸, 因为业务低锋期, 倒也还没造成什么大影响, 但难免对大表加字段产生了深深的恐惧;< br > 于是我们来探究下大表加字段究竟做了什么动作;</ p >
758
+ < h3 id ="背景 "> < a href ="#背景 " class ="headerlink " title ="背景 "> </ a > 背景</ h3 > < p > 因为业务的需求, 公司的一张大表需要添加字段, 先看了下表的大小, 行数到是还行, 才几十万, 但是, 因为有大字段的原因, 这个表有几十个G, 因此, 考验的时候就来了, 找了个业务不繁忙的时候, 果断添加了字段, 可是这个过程中, ddl执行了快一个半小时, 然后磁盘的iops快要爆炸, 因为业务低锋期, 倒也还没造成什么大影响, 但难免对大表加字段产生了深深的恐惧;< br > 于是我们来探究下大表加字段究竟做了什么动作;</ p >
760
759
< h3 id ="版本影响 "> < a href ="#版本影响 " class ="headerlink " title ="版本影响 "> </ a > 版本影响</ h3 > < p > 1.Mysql5.6之前, 直接修改表结构会导致整个数据库锁表, 具体内部步骤如下:(copy方式)</ p >
761
760
< ul >
762
761
< li > 首先创建新的临时表, 表结构通过命令alter table新定义的结构;</ li >
@@ -781,75 +780,13 @@ <h3 id="Online-DDL实现"><a href="#Online-DDL实现" class="headerlink" title="
781
780
< li > 等待打开当前表的所有只读事务提交;</ li >
782
781
< li > 创建索引结束</ li >
783
782
</ ul >
784
- < p > Online DDL实现:< br > 其实实质也是包含了copy和inplace的方式, 对于不支持online形式的, 也是直接采用了copy的方式;< br > online DDL主要包含了3个阶段;< br > 1.Prepare阶段:</ p >
785
- < ul >
786
- < li > 创建新的临时frm文件;</ li >
787
- < li > 持有EXCLUSIVE-MDL锁, 禁止读写;</ li >
788
- < li > 根据alter方式, 确定执行方式:(copy, online-rebuild, online-norebuild)</ li >
789
- < li > 更新数据字段内存对象;</ li >
790
- < li > 分配row_log对象记录增量;</ li >
791
- < li > 生成新的临时ibd文件;</ li >
792
- </ ul >
793
- < p > 2.ddl执行阶段:</ p >
794
- < ul >
795
- < li > 降级EXCLUSIVE-MDL锁, 允许读写;</ li >
796
- < li > 扫描old_table的聚集索引每一条记录rec;</ li >
797
- < li > 遍历新表的聚簇索引和二级索引, 逐一处理;</ li >
798
- < li > 根据rec构造对于的索引项;</ li >
799
- < li > 将构造索引项插入sort_buffer块;</ li >
800
- < li > 将sort_buffer块插入新的索引;</ li >
801
- < li > 处理ddl执行过程中产生的增量(仅rebuild类型需要)</ li >
802
- </ ul >
803
- < p > 3.commit阶段:</ p >
804
- < ul >
805
- < li > 升级到EXCLUSIVE-MDL锁, 禁止读写;</ li >
806
- < li > 重做最后row_log中最后一部分增量;</ li >
807
- < li > 更新innodb的数据字典表;</ li >
808
- < li > 提交事务(刷事务的redo日志)</ li >
809
- < li > 修改统计信息</ li >
810
- < li > rename临时idb文件, frm文件;</ li >
811
- < li > 变更完成;</ li >
812
- </ ul >
813
- < h3 id ="常用的ddl操作表 "> < a href ="#常用的ddl操作表 " class ="headerlink " title ="常用的ddl操作表 "> </ a > 常用的ddl操作表</ h3 > < table >
814
- < thead >
815
- < tr >
816
- < th > 操作</ th >
817
- < th > 并发DML</ th >
818
- < th > 算法</ th >
819
- < th > 备注</ th >
820
- </ tr >
821
- </ thead >
822
- < tbody >
823
- < tr >
824
- < td > 添加/删除索引</ td >
825
- < td > YES</ td >
826
- < td > online(no-rebuild)</ td >
827
- < td > 全文索引不支持(聚簇)</ td >
828
- </ tr >
829
- < tr >
830
- < td > 修改default值 修改列名 修改自增列值 添加/删除外键约束</ td >
831
- < td > YES</ td >
832
- < td > Noting</ td >
833
- < td > 仅需要修改元数据</ td >
834
- </ tr >
835
- < tr >
836
- < td > 添加/删除列 交换列顺序 修改NULL/NOT NULL 修改ROW-FORMAT 添加/修改PK Optimize table</ td >
837
- < td > YES</ td >
838
- < td > online(rebuild)</ td >
839
- < td > 由于记录格式改变, 需要重建表</ td >
840
- </ tr >
841
- < tr >
842
- < td > 修改列类型 删除PK 转换字符集 添加全文索引</ td >
843
- < td > NO</ td >
844
- < td > Copy</ td >
845
- < td > 需要锁表, 不支持online</ td >
846
- </ tr >
847
- </ tbody >
848
- </ table >
849
- < h3 id ="online-ddl总结 "> < a href ="#online-ddl总结 " class ="headerlink " title ="online ddl总结 "> </ a > online ddl总结</ h3 > < p > 1.实际上的优化就是对dml锁的细化, 只在某些关键部位进行全锁, 而不是整个阶段;< br > 2.然后运行并发读写后, 后面就需要留有一部分时间做增量的合并操作;< br > 3.若ddl异常, 可能会导致无法再次添加ddl的动作, 那是因为整个过程并不是一个原子操作, 而是复合式的, 所有ddl异常时, 需要清除残留的数据;</ p >
850
- < h3 id ="最终加表字段的注意事项 "> < a href ="#最终加表字段的注意事项 " class ="headerlink " title ="最终加表字段的注意事项 "> </ a > 最终加表字段的注意事项</ h3 > < p > 1.尽量选择流量小的业务时间段;< br > 2.如果可以的话, 进行主从切换来加字段最好;< br > 3.执行时,先看一下有无未提交的事务, 注意查看事务information_schema.innodb_trx表;< br > 4.加了之后, 随时关注下服务器日志情况;< br > 出现问题的, 可能会出现这样的sql会话;< br > < figure class ="highlight plain "> < table > < tr > < td class ="gutter "> < pre > < span class ="line "> 1</ span > < br > </ pre > </ td > < td class ="code "> < pre > < span class ="line "> waiting for table metadata lock</ span > < br > </ pre > </ td > </ tr > </ table > </ figure > </ p >
851
-
852
-
783
+ <!--noindex-->
784
+ < div class ="post-button text-center ">
785
+ < a class ="btn " href ="/2019/04/18/Mysql之八-超大表字段添加的要点/#more " rel ="contents ">
786
+ 阅读全文 »
787
+ </ a >
788
+ </ div >
789
+ <!--/noindex-->
853
790
854
791
855
792
</ div >
@@ -966,8 +903,7 @@ <h1 class="post-title" itemprop="name headline">
966
903
967
904
968
905
969
-
970
- < h3 id ="锁的种类 "> < a href ="#锁的种类 " class ="headerlink " title ="锁的种类 "> </ a > 锁的种类</ h3 > < p > 1.行锁;(InnoDb引擎有)</ p >
906
+ < h3 id ="锁的种类 "> < a href ="#锁的种类 " class ="headerlink " title ="锁的种类 "> </ a > 锁的种类</ h3 > < p > 1.行锁;(InnoDb引擎有)</ p >
971
907
< p > 2.表锁/元数据锁(MDL)</ p >
972
908
< figure class ="highlight plain "> < table > < tr > < td class ="gutter "> < pre > < span class ="line "> 1</ span > < br > </ pre > </ td > < td class ="code "> < pre > < span class ="line "> lock tables ... read/write</ span > < br > </ pre > </ td > </ tr > </ table > </ figure >
973
909
< p > 3.全局锁;</ p >
@@ -983,8 +919,13 @@ <h3 id="加锁规则-5-7版本以前-8-0系列"><a href="#加锁规则-5-7版本
983
919
< li > 优化2: 索引上的等值查询, 向右遍历时且最后一个值不满足等值条件的时候, next-key lock退化为间隙锁;</ li >
984
920
< li > bug1: 唯一索引上的范围查询会访问到不满足条件的第一个值为止;</ li >
985
921
</ ul >
986
- < h3 id ="具体分析看mysql实战45讲的21讲 "> < a href ="#具体分析看mysql实战45讲的21讲 " class ="headerlink " title ="具体分析看mysql实战45讲的21讲 "> </ a > 具体分析看mysql实战45讲的21讲</ h3 >
987
-
922
+ <!--noindex-->
923
+ < div class ="post-button text-center ">
924
+ < a class ="btn " href ="/2019/04/16/Mysql之七-锁的种类及加锁规则汇总/#more " rel ="contents ">
925
+ 阅读全文 »
926
+ </ a >
927
+ </ div >
928
+ <!--/noindex-->
988
929
989
930
990
931
</ div >
0 commit comments