MySQL中dd::columns表结构转table过程及应用详解


Posted in MySQL onSeptember 23, 2022

一、MySQL的dd表介绍

MySQL的dd表是用来存放表结构和各种建表信息的,客户端建的表都存在mysql.table和mysql.columns表里,还有一个表mysql.column_type_elements比较特殊,用来存放SET和ENUM类型的字段集合值信息。看一下下面这张表的mysql.columns表和mysql.column_type_elements信息。为了缩短显示长度,这里只展示几个重要的值。

#建表:
CREATE TABLE t1(id int  not null auto_increment primary key,col1 number,col2 VARCHAR(100),col3 pls_integer,
col4 enum('x','y') default 'x',col5 set('x1','y1'))  partition by hash(id) partitions 3;
SET SESSION debug='+d,skip_dd_table_access_check';
mysql> select name,ordinal_position,type,default_value_utf8,options,column_type_utf8 from mysql.columns where table_id=383;
+-------------+------------------+-----------------------+--------------------+-------------------+------------------+
| name        | ordinal_position | type                  | default_value_utf8 | options           | column_type_utf8 |
+-------------+------------------+-----------------------+--------------------+-------------------+------------------+
| col1        |                2 | MYSQL_TYPE_NEWDECIMAL | NULL               | interval_count=0; | decimal(65,0)    |
| col2        |                3 | MYSQL_TYPE_VARCHAR    | NULL               | interval_count=0; | varchar(100)     |
| col3        |                4 | MYSQL_TYPE_LONG       | NULL               | interval_count=0; | int              |
| col4        |                5 | MYSQL_TYPE_ENUM       | x                  | interval_count=2; | enum('x','y')    |
| col5        |                6 | MYSQL_TYPE_SET        | NULL               | interval_count=2; | set('x1','y1')   |
| DB_ROLL_PTR |                8 | MYSQL_TYPE_LONGLONG   | NULL               | NULL              |                  |
| DB_TRX_ID   |                7 | MYSQL_TYPE_INT24      | NULL               | NULL              |                  |
| id          |                1 | MYSQL_TYPE_LONG       | NULL               | interval_count=0; | int              |
+-------------+------------------+-----------------------+--------------------+-------------------+------------------+
8 rows in set (0.00 sec)

mysql.columns表说明如下:

ordinal_position是该字段在表里的偏移量,这里多了3个字段,DB_ROLL_PTRDB_TRX_IDid是用来执行undo的,记录了字段的版本信息。

default_value_utf8是用来保存默认值的。options里面有interval_count用来保存集合类型的数值数的。columns表的options的key一共有如下几种:

static const std::set<String_type> default_valid_option_keys = {
    "column_format", "geom_type",         "interval_count", "not_secondary",
    "storage",       "treat_bit_as_char", "zip_dict_id",    "is_array"};
mysql>  select * from mysql.column_type_elements where column_id=4286;
+-----------+---------------+------+
| column_id | element_index | name |
+-----------+---------------+------+
|      4286 |             1 | x    |
|      4286 |             2 | y    |
+-----------+---------------+------+
2 rows in set (0.01 sec)
<strong>#这里的column_id=4286是col4的id值,x和y分别对应了set定义时候的2个集合值。</strong>

二、代码跟踪

现在重新启动数据库,跟踪一下这个columns表怎么转为代码里面的TABLE的field对象。首先找到表的dd信息然后打开表获取field信息。

mysql> select * from t1;

输入该命令后找到columns表转为field的代码:

#0  fill_column_from_dd (
    thd=0x555558b35a06 <std::char_traits<char>::compare(char const*, char const*, unsigned long)+61>, 
    share=0x7fffe83f1b60, 
    col_obj=0x555558bb0a5e <std::__cxx11::basic_string<char, std::char_traits<char>, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> >::compare(std::__cxx11::basic_string<char, std::char_traits<char>, Stateless_allocator<char, dd::String_type_alloc, My_free_functor> > const&) const+142>, 
    null_pos=0x7fffe83f1880 "\005", null_bit_pos=32767, rec_pos=0x7fff2c05ac10 "explicit_encryption", 
    field_nr=0) at /mysql/sql/dd_table_share.cc:955
#1  0x00005555593c4c17 in fill_columns_from_dd (thd=0x7fff2c006890, share=0x7fff2cbf19e8, 
    tab_obj=0x7fff2cbb9b38) at /mysql/sql/dd_table_share.cc:1235
#2  0x00005555593c9e54 in open_table_def (thd=0x7fff2c006890, share=0x7fff2cbf19e8, table_def=...)
    at /mysql/sql/dd_table_share.cc:2408
#3  0x0000555558e76a13 in get_table_share (thd=0x7fff2c006890, db=0x7fff2cbeeff0 "db1", 
    table_name=0x7fff2cc03210 "t1", key=0x7fff2cbeed87 "db1", key_length=7, open_view=true, 
    open_secondary=false) at /mysql/sql/sql_base.cc:801
#4  0x0000555558e76f08 in get_table_share_with_discover (thd=0x7fff2c006890, table_list=0x7fff2cbee9b8, 
    key=0x7fff2cbeed87 "db1", key_length=7, open_secondary=false, error=0x7fffe83f1ea4)
    at /mysql/sql/sql_base.cc:889
#5  0x0000555558e7cd34 in open_table (thd=0x7fff2c006890, table_list=0x7fff2cbee9b8, 
    ot_ctx=0x7fffe83f2380) at /mysql/sql/sql_base.cc:3230
#6  0x0000555558e81769 in open_and_process_table (thd=0x7fff2c006890, lex=0x7fff2c01bdf0, 
    tables=0x7fff2cbee9b8, counter=0x7fff2c01be48, prelocking_strategy=0x7fffe83f2408, 
    has_prelocking_list=false, ot_ctx=0x7fffe83f2380)
    at /mysql/sql/sql_base.cc:5118
#7  0x0000555558e833bd in open_tables (thd=0x7fff2c006890, start=0x7fffe83f23f0, counter=0x7fff2c01be48, 
    flags=0, prelocking_strategy=0x7fffe83f2408)
    at /mysql/sql/sql_base.cc:5928
#8  0x0000555558e85626 in open_tables_for_query (thd=0x7fff2c006890, tables=0x7fff2cbee9b8, flags=0)
    at /mysql/sql/sql_base.cc:6904
#9  0x0000555559075720 in Sql_cmd_dml::prepare (this=0x7fff2cbef400, thd=0x7fff2c006890)
    at /mysql/sql/sql_select.cc:372
#10 0x00005555590760bf in Sql_cmd_dml::execute (this=0x7fff2cbef400, thd=0x7fff2c006890)
    at /mysql/sql/sql_select.cc:527
#11 0x0000555558fedc8e in mysql_execute_command (thd=0x7fff2c006890, first_level=true)
    at /mysql/sql/sql_parse.cc:4794
#12 0x0000555558fefe25 in dispatch_sql_command (thd=0x7fff2c006890, parser_state=0x7fffe83f3990, 
    update_userstat=false) at /mysql/sql/sql_parse.cc:5399
#13 0x0000555558fe52d3 in dispatch_command (thd=0x7fff2c006890, com_data=0x7fffe83f4b70, 
    command=COM_QUERY) at /mysql/sql/sql_parse.cc:2000
#14 0x0000555558fe3643 in do_command (thd=0x7fff2c006890)
    at /mysql/sql/sql_parse.cc:1448
#15 0x000055555920e200 in handle_connection (arg=0x555560a65790)
    at /mysql/sql/conn_handler/connection_handler_per_thread.cc:307
#16 0x000055555ae36375 in pfs_spawn_thread (arg=0x5555608a2e20)
    at /mysql/storage/perfschema/pfs.cc:2899
#17 0x00007ffff77a6609 in start_thread (arg=<optimized out>) at pthread_create.c:477
#18 0x00007ffff76cb163 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
<strong>#fill_column_from_dd函数里面最重要的是make_field函数,把字段从dd::Column转为table的field然后赋值给TABLE_SHARE。
  reg_field = make_field(*col_obj, charset, share, rec_pos, null_pos, null_bit_pos);</strong>

三、知识应用

session每次获取表的信息都是在第一次打开表的时候就做好了,下次如果表没有变化就从Table_cache直接获取表信息。现在假设我们要改col4字段的集合值又不想通过alter语句来执行,那就可以直接对dd表进行操作。注意,该操作对生产环境有很大风险,这里只用来进行知识实践,不能用来在生产环境实际操作。

把col4的x,y值改为a,b:首先试着插入col4=x的记录,现在还没更改dd表所以插入成功。

mysql> insert into t1 values(1,1,'aa',1,'x','x1');
Query OK, 1 row affected (0.03 sec)

接着开始改col4的集合值:

mysql> SET SESSION debug='+d,skip_dd_table_access_check';
Query OK, 0 rows affected (0.02 sec)
mysql> update mysql.columns set default_value_utf8='a' ,column_type_utf8='enum(\'a\',\'b\'))' where table_id=383 and name='col4';
Query OK, 1 row affected (0.03 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select name,ordinal_position,type,default_value_utf8,options,column_type_utf8 from mysql.columns where table_id=383;
+-------------+------------------+-----------------------+--------------------+-------------------+------------------+
| name        | ordinal_position | type                  | default_value_utf8 | options           | column_type_utf8 |
+-------------+------------------+-----------------------+--------------------+-------------------+------------------+
| col1        |                2 | MYSQL_TYPE_NEWDECIMAL | NULL               | interval_count=0; | decimal(65,0)    |
| col2        |                3 | MYSQL_TYPE_VARCHAR    | NULL               | interval_count=0; | varchar(100)     |
| col3        |                4 | MYSQL_TYPE_LONG       | NULL               | interval_count=0; | int              |
| col4        |                5 | MYSQL_TYPE_ENUM       | a                  | interval_count=2; | enum('a','b'))   |集合值已改
| col5        |                6 | MYSQL_TYPE_SET        | NULL               | interval_count=2; | set('x1','y1')   |
| DB_ROLL_PTR |                8 | MYSQL_TYPE_LONGLONG   | NULL               | NULL              |                  |
| DB_TRX_ID   |                7 | MYSQL_TYPE_INT24      | NULL               | NULL              |                  |
| id          |                1 | MYSQL_TYPE_LONG       | NULL               | interval_count=0; | int              |
+-------------+------------------+-----------------------+--------------------+-------------------+------------------+
8 rows in set (0.00 sec)

mysql> update mysql.column_type_elements set name='a' where column_id=4286 and element_index=1;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update mysql.column_type_elements set name='b' where column_id=4286 and element_index=2;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql>  select * from mysql.column_type_elements where column_id=4286;
+-----------+---------------+------+
| column_id | element_index | name |
+-----------+---------------+------+
|      4286 |             1 | a    |<strong>集合值已改</strong>
|      4286 |             2 | b    |<strong>集合值已改</strong>
+-----------+---------------+------+
2 rows in set (0.00 sec)

现在再插入一条col4=x的记录发现还是成功的,这是因为t1没有重新从dd表转为TABLE信息,需要重启后再试。

mysql> insert into t1 values(2,1,'aa',1,'x','x1');
Query OK, 1 row affected (0.02 sec)

重启数据库,然后登录。再次插入col4=x发现报错了,因为这时候的TABLE信息是重新从dd表转化的。

mysql> insert into t1 values(2,1,'aa',1,'x','x1');
ERROR 1265 (01000): Data truncated for column 'col4' at row 1

插入col4=a的记录成功,说明更改成功。

mysql> insert into t1 values(3,1,'aa',1,'a','x1');
Query OK, 1 row affected (0.02 sec)

查看建表信息,发现已经成功更改。

mysql> show create table t1;
+-------+-------------------------+
| Table | Create Table     |
+-------+-------------------------+
| t1    | CREATE TABLE `t1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `col1` decimal(65,0) DEFAULT NULL,
  `col2` varchar(100) DEFAULT NULL,
  `col3` int DEFAULT NULL,
  `col4` enum('a','b') DEFAULT 'a',更改成功
  `col5` set('x1','y1') DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
/*!50100 PARTITION BY HASH (`id`)
PARTITIONS 3 */ 
+-------+-------------------------+

四、总结

实际上更改表结构如果通过alter命令来改流程跟上面也是一样的,也是通过更新dd表来实现表结构的变更,这里只是从更底层来介绍。以上的操作在实际生产中不能直接操作,风险很大,会影响现有的记录和相关的功能。这里只是作为一个案例来更好的说明dd的工作流程,帮助大家遇到问题知道怎么从底层排查。

到此这篇关于MySQL中dd::columns表结构转table过程及应用详解的文章就介绍到这了,更多相关mysql dd::columns表结构内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

MySQL 相关文章推荐
MySQL root密码的重置方法
Apr 21 MySQL
MySQL Router的安装部署
Apr 24 MySQL
MySQL 重写查询语句的三种策略
May 10 MySQL
MySQL连表查询分组去重的实现示例
Jul 01 MySQL
MySQL令人大跌眼镜的隐式转换
Aug 23 MySQL
MySQL Server层四个日志的实现
Mar 31 MySQL
MySQL中优化SQL语句的方法(show status、explain分析服务器状态信息)
Apr 09 MySQL
MySQL 外连接语法之 OUTER JOIN
Apr 09 MySQL
MySQL创建管理RANGE分区
Apr 13 MySQL
mysql中如何用命令创建联合唯一索引
Apr 20 MySQL
MySQL的prepare使用以及遇到的bug
May 11 MySQL
MySQL使用IF语句及用case语句对条件并结果进行判断 
Sep 23 #MySQL
MySQL远程无法连接的一些常见原因总结
Sep 23 #MySQL
MySQL count(*)统计总数问题汇总
Sep 23 #MySQL
MySQL常用慢查询分析工具详解
Aug 14 #MySQL
了解MySQL查询语句执行过程(5大组件)
Aug 14 #MySQL
MySQL 原理与优化之Update 优化
Aug 14 #MySQL
MySql统计函数COUNT的具体使用详解
Aug 14 #MySQL
You might like
PHP mkdir()定义和用法
2009/01/14 PHP
PHP父类调用子类方法的代码例子
2014/04/09 PHP
浅析php设计模式之数据对象映射模式
2016/03/03 PHP
PHP数组遍历的几种常见方式总结
2019/02/15 PHP
微信公众平台开发教程④ ThinkPHP框架下微信支付功能图文详解
2019/04/10 PHP
JQuery与iframe交互实现代码
2009/12/24 Javascript
自己写的兼容ie和ff的在线文本编辑器类似ewebeditor
2012/12/12 Javascript
iframe的onreadystatechange事件在firefox下的使用
2014/04/16 Javascript
JS获取客户端IP地址、MAC和主机名的7个方法汇总
2014/07/21 Javascript
javascript中apply、call和bind的使用区别
2016/04/05 Javascript
简单讲解jQuery中的子元素过滤选择器
2016/04/18 Javascript
JQuery validate插件验证用户注册信息
2016/05/11 Javascript
详解Vue生命周期的示例
2017/03/10 Javascript
JavaScript 中 apply 、call 的详解
2017/03/21 Javascript
详解nodejs操作mongodb数据库封装DB类
2017/04/10 NodeJs
老生常谈Bootstrap媒体对象
2017/07/06 Javascript
详解VueRouter进阶之导航钩子和路由元信息
2017/09/13 Javascript
React中的refs的使用教程
2018/02/13 Javascript
vue项目中使用Svg的方法
2018/10/24 Javascript
说说Vue.js中的functional函数化组件的使用
2019/02/12 Javascript
vue中axios请求的封装实例代码
2019/03/23 Javascript
简单了解前端渐进式框架VUE
2020/07/20 Javascript
零基础写python爬虫之urllib2中的两个重要概念:Openers和Handlers
2014/11/05 Python
利用Python脚本在Nginx和uwsgi上部署MoinMoin的教程
2015/05/05 Python
Python获取统计自己的qq群成员信息的方法
2019/11/15 Python
Python3实现监控新型冠状病毒肺炎疫情的示例代码
2020/02/13 Python
pytorch实现MNIST手写体识别
2020/02/14 Python
websocket+sockjs+stompjs详解及实例代码
2018/11/30 HTML / CSS
欧洲最大的高尔夫零售商:American Golf
2019/09/02 全球购物
数据库专业英语
2012/11/30 面试题
秋季红领巾广播稿
2014/01/27 职场文书
浪漫婚礼主持词
2014/03/14 职场文书
医药销售自我评价200字
2014/09/11 职场文书
武侯祠导游词
2015/02/04 职场文书
2015年体育教师个人工作总结
2015/05/12 职场文书
2019个人半年工作总结
2019/06/21 职场文书