MySQL 8.3 支持不可见列。不可见列通常对查询隐藏,但可以通过明确引用来访问。
例如,假设应用程序使用 SELECT *
查询访问表,并且必须在不修改的情况下继续工作,即使表被修改以添加新的列,该应用程序不知道该列的存在。在 SELECT *
查询中,*
评估为所有表列,除了那些不可见的列,因此解决方案是将新列添加为不可见列。该列从 SELECT *
查询中“隐藏”,并且应用程序继续像以前一样工作。新的应用程序版本可以通过明确引用来访问不可见列。
以下部分详细介绍了 MySQL 如何处理不可见列。
列默认为可见的。要明确指定新列的可见性,请在 CREATE TABLE
或 ALTER TABLE
中使用 VISIBLE
或 INVISIBLE
关键字:
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
语句,请命名它们并分配值,就像可见的列一样。
关于列是否可见或不可见的信息可以从信息模式 EXTRA
列的 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
在表定义中显示不可见列,以版本特定的注释形式,包括 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 和 mysqlpump
使用 SHOW CREATE TABLE
,因此它们在转储表定义中包括不可见列。它们还包括不可见列值在转储数据中。
将转储文件重新加载到不支持不可见列的旧版本 MySQL 中时,版本特定的注释将被忽略,从而创建不可见列作为可见列。
MySQL 将不可见列视为二进制日志中的以下事件:
-
表创建事件包括不可见列的
INVISIBLE
属性。 -
不可见列在行事件中被视为可见列。它们根据
binlog_row_image
系统变量设置需要时包括。 -
当行事件被应用时,不可见列被视为可见列。
-
不可见列在计算写集时被视为可见列。特别是,写集包括在不可见列上定义的索引。
-
mysqlbinlog 命令包括列元数据中的可见性信息。