Documentation Home

13.1.20.10 不可见的列

从 MySQL 8.0.23 开始,MySQL 支持不可见列。不可见的列通常对查询是隐藏的,但如果明确引用则可以访问。在 MySQL 8.0.23 之前,所有列都是可见的。

作为不可见列何时可能有用的说明,假设应用程序使用SELECT * 查询来访问表,并且即使表被更改以添加应用程序不希望存在的新列,也必须不加修改地继续工作。在 SELECT *查询中,* 对所有表列求值,不可见的列除外,因此解决方案是将新列添加为不可见列。该列对查询保持隐藏SELECT *状态,应用程序继续像以前一样工作。如有必要,较新版本的应用程序可以通过显式引用来引用不可见列。

以下部分详细说明了 MySQL 如何处理不可见的列。

DDL 语句和不可见列

默认情况下,列是可见的。要显式指定新列的可见性,请使用VISIBLE orINVISIBLE关键字作为 or 的列定义的CREATE TABLE一部分 ALTER TABLE

CREATE TABLE t1 (
  i INT,
  j DATE INVISIBLE
) ENGINE = InnoDB;
ALTER TABLE t1 ADD COLUMN k INT INVISIBLE;

要更改现有列的可见性,请将 VISIBLEorINVISIBLE 关键字与其中一个ALTER TABLE 列修改子句一起使用:

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;

一张表必须至少有一个可见的列。试图使所有列不可见会产生错误。

不可见列支持常用的列属性: NULLNOT NULLAUTO_INCREMENT等。

生成的列可以是不可见的。

索引定义可以命名不可见列,包括索引PRIMARY KEYUNIQUE索引的定义。尽管一张表必须至少有一个可见列,但索引定义不需要有任何可见列。

从表中删除的不可见列以通常的方式从命名该列的任何索引定义中删除。

可以在不可见列上定义外键约束,外键约束可以引用不可见列。

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了,所以它确实出现在结果中。

对于创建新行的语句,不可见的列会被赋予其隐式默认值,除非明确引用并赋值。有关隐式默认值的信息,请参阅 隐式默认处理

对于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()列表必须提供与命名列数相同的值数。

对于LOAD DATAand LOAD XML,隐式默认赋值发生在缺少列列表或不包含不可见列的非空列列表的情况下。输入行不应包含不可见列的值。

要为前面的语句分配一个不同于隐式默认值的值,请在列列表中显式命名不可见列并为其提供一个值。

INSERT INTO ... SELECT *并且 REPLACE INTO ... SELECT *不包括不可见的列,因为 *不包括不可见的列。隐式默认分配如前所述发生。

对于插入或忽略新行,或者替换或修改现有行的语句,基于PRIMARY KEYorUNIQUE索引中的值,MySQL 将不可见列与可见列一样对待:不可见列参与键值比较。具体来说,如果新行与现有行的唯一键值具有相同的值,则无论索引列是可见还是不可见,都会发生这些行为:

要更新 UPDATE语句的不可见列,请为它们命名并分配一个值,就像可见列一样。

不可见的列元数据

有关列是可见还是不可见的信息可从表或输出的EXTRA列中获得 。例如: INFORMATION_SCHEMA.COLUMNSSHOW 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在表定义中显示不可见的列,并 INVISIBLE在特定于版本的注释中使用关键字:

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

mysqldumpmysqlpump useSHOW CREATE TABLE,因此它们在转储表定义中包含不可见列。它们还在转储数据中包含不可见的列值。

将转储文件重新加载到不支持不可见列的旧版本 MySQL 会导致忽略特定于版本的注释,从而将任何不可见列创建为可见。

二进制日志和不可见的列

对于二进制日志中的事件,MySQL 如下处理不可见列:

  • 表创建事件包括 INVISIBLE不可见列的属性。

  • 不可见列在行事件中被视为可见列。如果需要,根据 binlog_row_image系统变量设置包含它们。

  • 应用行事件时,不可见列被视为行事件中的可见列。特别是,根据 slave_rows_search_algorithms 系统变量设置选择要使用的算法和索引。

  • 在计算 writesets 时,不可见列被视为可见列。特别是,writesets 包括在不可见列上定义的索引。

  • mysqlbinlog命令包括列元数据中的可见性 。