15.1.20.10 不可见列
MySQL 8.4 支持不可见列。不可见列通常被隐藏在查询中,但可以通过明确引用来访问。
假设一个应用程序使用SELECT *查询来访问表,并且必须继续工作而不需要修改,即使表被添加了新的列,该应用程序不知道该列的存在。在SELECT *查询中,*评估为所有表列,除了不可见列,所以解决方案是将新列添加为不可见列。该列仍然从SELECT *查询中被隐藏,但应用程序继续工作如之前。 newer 版本的应用程序可以通过明确引用来访问不可见列。
以下部分详细介绍了 MySQL 对不可见列的处理方式。
DDL 语句和不可见列
列默认可见。要明确指定新列的可见性,使用CREATE TABLE或ALTER TABLE语句中的VISIBLE或INVISIBLE关键字:
CREATE TABLE t1 (
i INT,
j DATE INVISIBLE
) ENGINE = InnoDB;
ALTER TABLE t1 ADD COLUMN k INT INVISIBLE;
要更改现有列的可见性,使用ALTER TABLE语句中的VISIBLE或INVISIBLE关键字和列修改子句:
ALTER TABLE t1 CHANGE COLUMN j j DATE VISIBLE;
ALTER TABLE t1 MODIFY COLUMN j DATE INVISIBLE;
ALTER TABLE t1 ALTER COLUMN j SET VISIBLE;
表必须至少有一个可见的列。尝试使所有列不可见将产生错误。
不可见列支持通常的列属性:NULL,NOT NULL,AUTO_INCREMENT等等。
生成列可以不可见。
索引定义可以命名不可见列,包括PRIMARY KEY和UNIQUE索引定义。虽然表必须至少有一个可见的列,但索引定义不需要任何可见的列。
从表中删除不可见列将在通常的方式下删除该列对应的索引定义。
外键约束可以定义在不可见列上,并且外键约束可以引用不可见列。
CHECK约束可以定义在不可见列上。对于新或修改的行,如果违反了不可见列上的CHECK约束将产生错误。
CREATE TABLE ... LIKE 包含不可见列,并且在新表中不可见。
CREATE TABLE ... SELECT 不包含不可见列,除非它们在 SELECT 部分中被明确引用。然而,即使被明确引用,在现有表中不可见的列在新表中仍然可见:
mysql> CREATE TABLE t1 (col1 INT, col2 INT INVISIBLE);
mysql> CREATE TABLE t2 AS SELECT col1, col2 FROM t1;
mysql> SHOW CREATE TABLE t2\G
*************************** 1. row ***************************
Table: t2
Create Table: CREATE TABLE `t2` (
`col1` int DEFAULT NULL,
`col2` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
如果需要保留不可见性,请在 CREATE TABLE 部分的 CREATE TABLE ... SELECT 语句中提供不可见列的定义:
mysql> CREATE TABLE t1 (col1 INT, col2 INT INVISIBLE);
mysql> CREATE TABLE t2 (col2 INT INVISIBLE) AS SELECT col1, col2 FROM t1;
mysql> SHOW CREATE TABLE t2\G
*************************** 1. row ***************************
Table: t2
Create Table: CREATE TABLE `t2` (
`col1` int DEFAULT NULL,
`col2` int DEFAULT NULL /*!80023 INVISIBLE */
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
视图可以通过明确在 SELECT 语句中引用不可见列来引用不可见列。修改一个列的可见性后定义了该列引用的视图不会改变视图行为。
DML 语句和不可见列
对于 SELECT 语句,不可见列不属于结果集除非在选择列表中被明确引用。在选择列表中,* 和 简写不会包含不可见列。自然连接也不包含不可见列。tbl_ name.*
请考虑以下语句序列:
mysql> CREATE TABLE t1 (col1 INT, col2 INT INVISIBLE);
mysql> INSERT INTO t1 (col1, col2) VALUES(1, 2), (3, 4);
mysql> SELECT * FROM t1;
+------+
| col1 |
+------+
| 1 |
| 3 |
+------+
mysql> SELECT col1, col2 FROM t1;
+------+------+
| col1 | col2 |
+------+------+
| 1 | 2 |
| 3 | 4 |
+------+------+
第一个SELECT 语句不引用不可见的列col2(因为* 不包括不可见的列),因此col2 不会出现在语句结果中。第二个SELECT 语句明确引用col2,因此该列将出现在结果中。
TABLE t1 语句的输出与第一个SELECT 语句相同。由于没有办法在TABLE 语句中指定列,因此TABLE 语句从不显示不可见的列。
对于创建新行的语句,不可见的列将被隐式分配默认值,除非明确引用并赋予值。关于隐式默认值的信息,请参阅隐式默认处理。
对于INSERT(和REPLACE,对于非替换行),隐式默认分配发生在缺省列列表、空列列表或不包含不可见列的非空列列表的情况下:
CREATE TABLE t1 (col1 INT, col2 INT INVISIBLE);
INSERT INTO t1 VALUES(...);
INSERT INTO t1 () VALUES(...);
INSERT INTO t1 (col1) VALUES(...);
对于前两个INSERT语句,VALUES()列表必须提供每个可见列的值,并且不能包含不可见列。对于第三个INSERT语句,VALUES()列表必须提供与命名列相同数量的值;同样,当使用VALUES ROW()时,也需要遵循这个规则。
对于LOAD DATA和LOAD XML,隐式默认分配发生在缺少列列表或非空列列表中不包含不可见列的情况下。输入行不能包含不可见列的值。
要为前述语句分配其他于隐式默认的值,请明确地在列列表中命名不可见列,并提供该列的值。
INSERT INTO ... SELECT *和REPLACE INTO ... SELECT *不包含不可见列,因为*不包括不可见列。隐式默认分配遵循前述描述。
对于基于 PRIMARY KEY 或 UNIQUE 索引中的值插入或忽略新行,或者替换或修改现有行的语句,MySQL 对不可见列和可见列一样对待:不可见列参与键值比较。具体来说,如果一个新行与现有行在唯一键值上具有相同值,这些行为是否会发生取决于索引列是否可见:
要为UPDATE 语句更新不可见列,需要像对可见列一样命名它们并分配值。
可以从信息_schema的COLUMNS表或SHOW COLUMNS输出中获取关于列是否可见或不可见的信息。例如:
mysql> SELECT TABLE_NAME, COLUMN_NAME, EXTRA
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'test' AND TABLE_NAME = 't1';
+------------+-------------+-----------+
| TABLE_NAME | COLUMN_NAME | EXTRA |
+------------+-------------+-----------+
| t1 | i | |
| t1 | j | |
| t1 | k | INVISIBLE |
+------------+-------------+-----------+
默认情况下,列是可见的,因此在这种情况下,EXTRA 不显示可见性信息。在不可见列的情况下,EXTRA 显示INVISIBLE。
SHOW CREATE TABLE 在表定义中显示不可见列,带有版本特定的注释:
mysql> SHOW CREATE TABLE t1\G
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`i` int DEFAULT NULL,
`j` int DEFAULT NULL,
`k` int DEFAULT NULL /*!80023 INVISIBLE */
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
mysqldump 使用 SHOW CREATE TABLE,因此它们在dumped表定义中包含不可见列。它们还包括dumped数据中的不可见列值。
将dump文件重新加载到不支持不可见列的 MySQL 旧版本中时,将忽略版本特定的注释,从而创建任何不可见列为可见。
二进制日志和不可见列
MySQL 对于二进制日志中的事件对不可见列的处理如下:
-
表创建事件包括不可见列的
INVISIBLE属性。 -
不可见的列被视为可见的列在行事件中。它们将根据
binlog_row_image系统变量设置是否包括。 -
当应用行事件时,不可见的列被视为可见的列在行事件中。
-
不可见的列在计算写集时被视为可见的列。特别是,写集包括不可见列上的索引定义。
-
mysqlbinlog命令包括列元数据中的可见性。