数据字典
对于MySQL的系统库都不会陌生,因为是基本框架,支撑着MySQL有效运行。这些系统库提供诸多功能,如:账号,表,存储过程,表空间,性能监控,配置 等基础信息。系统库目前有4个大类schema组成:mysql,information_schema,performance_schema,sys。都有各自的特性和运行模式。
-
mysql
最基本的基础元数据元表,它包含一些表存储MySQL服务器在运行时所需的信息。这些表InnoDB引擎utf8字符集的实际物理储存表(在MySQL8.0版本中已经去掉MyISAM引擎)。 -
INFORMATION_SCHEMA:
提供对数据库元数据、MySQL服务器的信息(如数据库或表的名称、列的数据类型或访问权限)的访问。有时用于此信息的其他术语是数据字典和系统目录。视图组成。DDL是不允许执行的。 -
Performance Schema:
MySQL性能模式是一种在低级别上监视MySQL服务器执行的特性。内存表组成。DDL是不允许执行的。 -
sys
这是帮助dba和开发人员解释性能模式收集的数据的对象。Sys对象可用于典型的调优和诊断用例。视图组成。DDL是不允许执行的。
从上述结构中,可以判断,mysql schema就是最核心的驱动表。但实际运行当中,这些数据字典表是不可见。考虑到安全问题和维护元数据正确性,避免随意更改,可能破坏整个系统,不在debug模式下,无法直接访问的。
同时不能人为 DDL和更改操作,也不会出现在SHOW表的输出中,也没有列在INFORMATION_SCHEMA.TABLES中。但可通过INFORMATION_SCHEMA的视图访问数据字典元数据。
WL#6391: Protect Data Dictionary tables
This WL restricts the availability of DD information to the users. We do not
want to expose DD tables directly to users, so access must happen through I_S.
Additionally, access to the system schema and tablespace is limited.
从MySQL 8.0开始,这些表是InnoDB(事务)表。以前版本是MyISAM(非事务性)表,因为事务特性,对于数据一致性不会产生任何影响。目前为止的MySQL 8.0的数据字典表如下:
开启方式
如访问,会提示如下错误:
mysql> SELECT name FROM mysql.tables where schema_id=1 AND hidden='System';
ERROR 3554 (HY000): Access to data dictionary table 'mysql.tables' is rejected.
权限判断:mysql-8.0.31\sql\dd\impl\dictionary_impl.cc
bool Dictionary_impl::is_dd_table_access_allowed(bool is_dd_internal_thread,
bool is_ddl_statement,
const char *schema_name,
size_t schema_length,
const char *table_name) const {
/*
From WL#6391, we have the following matrix describing access:
For performance reasons, we first check the schema
name to shortcut the evaluation. If the table is not in
the 'mysql' schema, we don't need any further checks. Same for
checking for internal threads - an internal thread has full
access. We also allow access if the appropriate debug flag
is set.
*/
if (schema_length != MYSQL_SCHEMA_NAME.length ||
strncmp(schema_name, MYSQL_SCHEMA_NAME.str, MYSQL_SCHEMA_NAME.length) ||
is_dd_internal_thread ||
DBUG_EVALUATE_IF("skip_dd_table_access_check", true, false))
return true;
开始方式:
采用MySQL源码编译,同时添加参数-DWITH_DEBUG=1配置选项。可以通过执行:mysqld --help来检查是否开启调试。
shell# mysqld --help | grep debug
mysqld Ver 8.0.31-debug for Linux on x86_64 (Source distribution)
或
采用tar包下mysqld-debug执行文件,重新启动服务
mysqld-debug --defaults-file=/etc/my8.0.cnf --user=mysql &
权限开启
mysql> SET SESSION debug='+d,skip_dd_table_access_check';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @@debug;
+------------------------------+
| @@DEBUG |
+------------------------------+
| d,skip_dd_table_access_check |
+------------------------------+
1 row in set (0.01 sec)
#访问基础表
mysql> SELECT name FROM mysql.tables where schema_id=1 AND hidden='System';
。。。
DD 表名 | 说明 |
---|---|
catalogs | 目录信息。 |
character_sets | 可用字符集的信息。 |
check_constraints | 关于表上定义的CHECK约束的信息。 |
collations | 关于每个字符集的排序规则的信息 。 |
column_statistics | 列值的直方图统计信息。 |
column_type_elements | 关于列使用的类型的信息。 |
columns | 关于表中列的信息。 |
dd_properties | 标识数据字典属性的表,例如它的版本。服务器使用它来确定是否必须将数据字典升级到较新的版本。 |
events | 关于事件调度器事件的信息。 |
foreign_keys, foreign_key_column_usage | 关于外键的信息。 |
index_column_usage | 索引使用的列的信息。 |
index_partitions | 关于索引使用的分区的信息。 |
index_stats | 用于存储在执行ANALYZE TABLE时生成的动态索引统计信息。 |
indexes | 关于表索引的信息。 |
innodb_ddl_log | 存储DDL操作的崩溃安全日志。 |
parameter_type_elements | 关于存储过程和函数参数的信息,以及关于存储函数返回值的信息。 |
parameters | 存储过程和函数的相关信息。 |
resource_groups | 资源组信息。 |
schemata | 关于schemata的信息。 |
st_spatial_reference_systems | 空间数据的可用空间参考系统的信息。 |
table_partition_values | 表分区使用的值的信息。 |
table_partitions | 关于表使用的分区的信息。 |
table_stats | 执行ANALYZE table时生成的动态表统计信息。 |
tables | 关于数据库中表的信息。 |
tablespace_files | 表空间使用的文件信息。 |
tablespaces | 活动表空间的信息。 |
triggers | 触发器信息。 |
view_routine_usage | 关于视图和视图使用的存储函数之间的依赖关系的信息。 |
view_table_usage | 用于跟踪视图及其底层表之间的依赖关系。 |
表结构
InnoDB 引擎 utf8字符集
mysql> SHOW CREATE TABLE mysql.tables\G;
*************************** 1. row ***************************
Table: tables
Create Table: CREATE TABLE `tables` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`schema_id` bigint unsigned NOT NULL,
`name` varchar(64) CHARACTER SET utf8 COLLATE utf8_tolower_ci NOT NULL,
`type` enum('BASE TABLE','VIEW','SYSTEM VIEW') COLLATE utf8_bin NOT NULL,
`engine` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`mysql_version_id` int unsigned NOT NULL,
。。。
PRIMARY KEY (`id`),
UNIQUE KEY `schema_id` (`schema_id`,`name`),
UNIQUE KEY `engine` (`engine`,`se_private_id`)
) /*!50100 TABLESPACE `mysql` */ ENGINE=InnoDB AUTO_INCREMENT=2412 DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0 ROW_FORMAT=DYNAMIC
1 row in set (0.00 sec)
Debug模式下允许更改操作
正常模式下允许呈现基础表名,但无法进行操作,必须在debug模式下:
mysql> UPDATE mysql.tables SET hidden='Visible' WHERE name='catalogs';
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings:
总结
Data Dictionary Table是系统的根本,同时数据也非常敏感,必须保护这些表不受DDL的影响,同时不受人为的更改。不了解底层实现原理下,一旦更改那就是灾难性的,所以应该保持隐藏。
但对于开源来说,围绕这些基础表,理解设计理念,通过更改定义和字段,实现更多的便利功能。
参考
https://dev.mysql.com/worklog/task/?id=6391
https://dev.mysql.com/doc/refman/8.0/en/system-schema.html
https://dev.mysql.com/doc/refman/8.0/en/dbug-package.html
https://dev.mysql.com/doc/dev/mysql-server/latest/classdd_1_1tables_1_1DD__properties.html