MySQL 9.0 支持不可见列。不可见列通常对查询隐藏,但如果显式引用则可以访问。
作为不可见列可能很有用的一个示例,假设应用程序使用 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
语句,不可见列不是结果集的一部分,除非在 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
在 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
语句的不可见列,请命名它们并分配值,就像对可见列一样。
有关列是可见的还是不可见的信息,可从 Information Schema 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 命令在列元数据中包含可见性。