MySQL 8.4 支持不可见列。不可见列通常对查询隐藏,但如果明确引用,则可以访问。
为了说明不可见列何时有用,假设应用程序使用 SELECT *
查询来访问表,并且即使在修改表以添加应用程序不希望存在的新的列后,也必须继续工作,而无需修改。在 SELECT *
查询中,*
会解析为所有表列,但不可见列除外,因此解决方案是将新列添加为不可见列。该列在 SELECT *
查询中保持““隐藏”,并且应用程序继续像以前一样工作。如果需要,较新版本的应用程序可以通过明确引用不可见列来引用它。
以下各节详细介绍了 MySQL 如何处理不可见列。
默认情况下,列是可见的。若要显式指定新列的可见性,请使用 VISIBLE
或 INVISIBLE
关键字作为 CREATE TABLE
或 ALTER TABLE
列定义的一部分
CREATE TABLE t1 (
i INT,
j DATE INVISIBLE
) ENGINE = InnoDB;
ALTER TABLE t1 ADD COLUMN k INT INVISIBLE;
要更改现有列的可见性,请将 VISIBLE
或 INVISIBLE
关键字与 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;
表必须至少有一个可见列。尝试将所有列设为不可见会产生错误。
不可见列支持常用的列属性: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
语句中明确引用不可见列来引用它们。在定义引用该列的视图后更改列的可见性不会更改视图行为。
对于 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()
而不是 VALUES()
时也是如此。
对于 LOAD DATA
和 LOAD XML
,如果缺少列列表或非空列列表不包含不可见列,则会发生隐式默认值分配。输入行不应包含不可见列的值。
要为前面的语句分配除隐式默认值以外的值,请在列列表中明确命名不可见列并为其提供值。
INSERT INTO ... SELECT *
和 REPLACE INTO ... SELECT *
不包括不可见列,因为 *
不包括不可见列。隐式默认值分配如前面所述。
对于根据 PRIMARY KEY
或 UNIQUE
索引中的值插入或忽略新行,或者替换或修改现有行的语句,MySQL 将不可见列与可见列同等对待:不可见列参与键值比较。具体来说,如果新行与现有行的唯一键值相同,则无论索引列是可见的还是不可见的,都会发生以下行为:
要更新 UPDATE
语句的不可见列,请像对待可见列一样命名它们并分配值。
有关列是可见的还是不可见的信息可从信息架构 COLUMNS
表的 EXTRA
列或 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
在表定义中显示不可见列,并在特定于版本的注释中使用 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
mysqldump 使用 SHOW CREATE TABLE
,因此它们在转储的表定义中包含不可见列。它们还在转储的数据中包含不可见列值。
将转储文件重新加载到不支持不可见列的旧版本 MySQL 中会导致特定于版本的注释被忽略,从而将所有不可见列创建为可见列。
对于二进制日志中的事件,MySQL 如下处理不可见列:
表创建事件包括不可见列的
INVISIBLE
属性。在行事件中,不可见列的处理方式与可见列相同。根据
binlog_row_image
系统变量设置,如果需要,将包含它们。应用行事件时,不可见列的处理方式与行事件中的可见列相同。
计算写入集时,不可见列的处理方式与可见列相同。特别是,写入集包括在不可见列上定义的索引。
mysqlbinlog 命令在列元数据中包含可见性。