#### 13.1.20.10 不可见的列

[](<>)

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

为了说明什么时候不可见的列可能有用，假设应用程序使用`选择 *`访问表的查询，并且即使表被更改以添加应用程序不希望出现的新列，也必须继续工作而不进行修改。在一个`选择 *`查询`*`计算所有表列，除了那些不可见的列，因此解决方案是将新列添加为不可见列。该列仍然“隐藏”`选择 *`查询，并且应用程序继续像以前一样工作。如有必要，较新版本的应用程序可以通过显式引用来引用不可见列。

以下部分详细介绍了 MySQL 如何处理不可见列。

-   [DDL 语句和不可见列](invisible-columns.html#invisible-column-ddl-statements)

-   [DML 语句和不可见列](invisible-columns.html#invisible-column-dml-statements)

-   [不可见的列元数据](invisible-columns.html#invisible-column-metadata)

-   [二进制日志和不可见列](invisible-columns.html#invisible-column-binary-logging)

##### DDL 语句和不可见列

默认情况下，列是可见的。要显式指定新列的可见性，请使用`可见的`要么`无形的`关键字作为列定义的一部分[`创建表`](create-table.html)要么[`更改表`](alter-table.html)：

```
CREATE TABLE t1 (
  i INT,
  j DATE INVISIBLE
) ENGINE = InnoDB;
ALTER TABLE t1 ADD COLUMN k INT 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;
```

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

不可见列支持通常的列属性：`空值`,`非空`,`自动递增`，等等。

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

索引定义可以命名不可见的列，包括定义`首要的关键`和`独特`索引。尽管表必须至少有一个可见列，但索引定义不需要任何可见列。

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

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

`查看`可以在不可见的列上定义约束。对于新的或修改的行，违反`查看`对不可见列的约束会产生错误。

[`创建表...喜欢`](create-table-like.html)包括不可见的列，它们在新表中是不可见的。

[`创建表...选择`](create-table-select.html)不包括不可见的列，除非它们在[`选择`](select.html)部分。但是，即使显式引用，在现有表中不可见的列在新表中也是可见的：

```
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.html)的一部分[`创建表...选择`](create-table-select.html)陈述：

```
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
```

视图可以通过在`选择`定义视图的语句。在定义引用列的视图之后更改列的可见性不会更改视图行为。

##### DML 语句和不可见列

为了[`选择`](select.html)语句，除非在选择列表中明确引用，否则不可见列不是结果集的一部分。在选择列表中，`*`和`*`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.html)不引用不可见列`col2`在选择列表中（因为`*`不包括不可见的列），所以`col2`不会出现在语句结果中。第二[`选择`](select.html)确实参考`col2`，所以它确实出现在结果中。

对于创建新行的语句，除非显式引用并分配值，否则会为不可见列分配其隐式默认值。有关隐式默认值的信息，请参阅[隐式默认处理](data-type-defaults.html#data-type-defaults-implicit).

为了[`插入`](insert.html)（和[`代替`](replace.html)，对于未替换的行），隐式默认分配发生在缺少列列表、空列列表或不包含不可见列的非空列列表中：

```
CREATE TABLE t1 (col1 INT, col2 INT INVISIBLE);
INSERT INTO t1 VALUES(...);
INSERT INTO t1 () VALUES(...);
INSERT INTO t1 (col1) VALUES(...);
```

对于前两个[`插入`](insert.html)声明，`值（）`list 必须为每个可见列提供一个值，并且没有不可见列。对于第三个[`插入`](insert.html)声明`值（）`list 必须提供与命名列数相同数量的值。

为了[`加载数据`](load-data.html)和[`加载 XML`](load-xml.html)，隐式默认分配发生在缺少列列表或不包含不可见列的非空列列表中。输入行不应包含不可见列的值。

要为上述语句分配除隐式默认值之外的值，请显式命名列列表中的不可见列并为其提供值。

[`插入 ... 选择 *`](insert-select.html)和[`替换成 ... 选择 *`](replace.html)不包括不可见的列，因为`*`不包括不可见的列。隐式默认分配如前所述发生。

对于插入或忽略新行或替换或修改现有行的语句，基于`首要的关键`要么`独特`索引，MySQL 将不可见列视为可见列：不可见列参与键值比较。具体来说，如果新行与现有行的唯一键值具有相同的值，则无论索引列是可见还是不可见，都会发生这些行为：

-   随着`忽视`修饰符，[`插入`](insert.html),[`加载数据`](load-data.html)， 和[`加载 XML`](load-xml.html)忽略新行。

-   [`代替`](replace.html)用新行替换现有行。随着`代替`修饰符，[`加载数据`](load-data.html)和[`加载 XML`](load-xml.html)照着做。

-   [`插入 ... 在重复密钥更新时`](insert-on-duplicate.html)更新现有行。

    更新不可见列[`更新`](update.html)语句，命名它们并分配一个值，就像可见列一样。

##### 不可见的列元数据

[](<>)[](<>)

有关列是可见还是不可见的信息可从`额外的`的列[`INFORMATION_SCHEMA.COLUMNS`](information-schema-columns-table.html)表或[`显示列`](show-columns.html)输出。例如：

```
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 |
+------------+-------------+-----------+
```

默认情况下，列是可见的，所以在这种情况下，`额外的`不显示可见性信息。对于不可见的列，`额外的`显示`无形的`.

`显示创建表`在表定义中显示不可见的列，其中`无形的`特定于版本的注释中的关键字：

```
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
```

[**mysql转储**](mysqldump.html)和`mysql泵`采用`显示创建表`，因此它们在转储表定义中包含不可见列。它们还包括转储数据中的不可见列值。

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

##### 二进制日志和不可见列

[](<>)[](<>)

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

-   表创建事件包括`无形的`不可见列的属性。

-   不可见列被视为行事件中的可见列。如果需要，它们会根据[`binlog_row_image`](replication-options-binary-log.html#sysvar_binlog_row_image)系统变量设置。

-   应用行事件时，不可见列被视为行事件中的可见列。特别是，要使用的算法和索引是根据[`slave_rows_search_algorithms`](replication-options-replica.html#sysvar_slave_rows_search_algorithms)系统变量设置。

-   在计算写入集时，不可见列被视为可见列。特别是，写集包括在不可见列上定义的索引。

-   这[**mysqlbinlog**](mysqlbinlog.html)命令包括列元数据中的可见性。
