0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

讨论MySQL 8.0中的几个隐藏的特性

OSC开源社区 来源:Percona 官网博客 2023-08-10 10:07 次阅读

隐藏列

8.0.23 新增隐藏列特性。什么是隐藏列?它基本上是一个表的常规列,具有自己的名称和数据类型。

它像任何其他常规列一样处理和更新,唯一的区别是对应用程序不可见。

换句话说,只有在 SELECT 语句中明确搜索它时,才能访问它;否则,它就像一个不存在的列。

这个定义看起来很奇怪,但如果提供一个这个特性的真实使用案例,一切都应该更清晰。

假设您的应用程序代码中有SELECT *查询。作为经验丰富的数据库开发人员,您应该知道这种查询不应存在于任何生产代码中。

典型的问题是,当您需要更改表架构,添加或删除列,或者更糟的是在其他列中间添加新列时。

抓取到你应用程序变量中的字段位置可能会完全打破应用程序或触发意外的错误行为。

这就是您需要避免在应用程序中使用SELECT *的原因。

在这种情况下,如果您需要避免更改应用程序代码以匹配新表架构,可以将新列添加为隐藏列,它不会返回给客户端,因为您的查询没有明确搜索它。

所以,您的应用程序不会失败或出现奇怪的行为。

而这,就是隐藏列的用武之地。

您需要在列定义中使用INVISIBLE关键字。

当您需要将列设置为可见时,需要使用VISIBLE关键字。

让我们看一个例子。 我们创建一个表并插入一些行:

mysql> CREATE TABLE articles (
  id INT UNSIGNED AUTO_INCREMENT,
  ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  article TEXT,
  PRIMARY KEY(id)
);
Query OK, 0 rows affected (0.03 sec)

mysql> INSERT INTO articles(article) VALUES
  ("This is first article"),
  ("This is second article"),
  ("This is third article");
Query OK, 3 rows affected (0.01 sec)  
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM articles;
+----+---------------------------+------------------------------+
| id | ts         | article        |
+----+---------------------------+------------------------------+
| 1 | 2023-07-28 1303 | This is first article |
| 2 | 2023-07-28 1303 | This is second article |
| 3 | 2023-07-28 1303 | This is third article |
+----+---------------------------+------------------------------+
有时,我们决定必须在ts列之后向表中添加一个新的字段title。

为了避免我们的应用程序因SELECT *和新添加的中间列等情况失效,我们必须将title列创建为INVISIBLE。
mysql> ALTER TABLE articles ADD COLUMN title VARCHAR(200) INVISIBLE AFTER ts;
Query OK, 0 rows affected (0.06 sec)  
Records: 0  Duplicates: 0  Warnings: 0

为新列提供一些值:

mysql> UPDATE articles SET title='Title 1' WHERE id=1;
UPDATE articles SET title='Title 2' WHERE id=2; 
UPDATE articles SET title='Title 3' WHERE id=3;

现在看看表架构:

CREATE TABLE `articles` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `ts` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `title` varchar(200) DEFAULT NULL /*!80023 INVISIBLE */,
  `article` text,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
你可以看到,该列被正确地标记了INVISIBLE关键字。 再试一次SELECT *:
mysql> SELECT * FROM articles;
+----+---------------------------+------------------------------+
| id | ts         | article        |
+----+---------------------------+------------------------------+
| 1 | 2023-07-28 1303 | This is first article |
| 2 | 2023-07-28 1303 | This is second article |
| 3 | 2023-07-28 1303 | This is third article |
+----+---------------------------+------------------------------+

你看,该列没有返回。这允许schema改变后查询不会失败。

如果你想看title,你必须明确寻址该字段:

mysql> SELECT id, ts, title, article FROM articles;
+----+---------------------------+-----------+------------------------------+
| id | ts                  | title   | article                |
+----+---------------------------+-----------+------------------------------+
|  1 | 2023-07-28 1303 | Title 1 | This is first article  |
|  2 | 2023-07-28 13:15:03 | Title 2 | This is second article |
|  3 | 2023-07-28 1303 | Title 3 | This is third article  |
+----+---------------------------+-----------+------------------------------+

使用以下 DDL 将列设置为可见:

mysql> ALTER TABLE articles MODIFY COLUMN title varchar(200) VISIBLE;
记住,隐藏列像任何其他常规列一样处理,所以您可以随时读取和更新它们。

关于隐形性的元数据在information_schema中可用,INVISIBLE/VISIBLE关键字在 binlog 中保留,以便正确复制所有更改。

生成的隐藏主键

这个特性在 MySQL 8.0.30 开始提供。生成的隐藏主键(GIPK)是一种特殊的隐藏列,仅适用于 InnoDB 表。

没有主键的情况下创建 InnoDB 表,往往不是一个好的选择。

我们强烈建议您的表中始终创建显式主键。您可能还知道,如果您不提供主键,InnoDB 会创建一个隐藏的主键,但是 GIPK 提供的新特性使主键可以变得可用和最后可见。

相反,隐含创建的早期隐藏主键既不能成为可用的也不能成为可见的。

该功能对于强制缺乏经验的用户的 InnoDB 表都具有显式主键很有用,即使是隐藏的。

让我们看看它是如何工作的。

默认情况下,此功能被禁用,因此 MySQL 将继续像过去一样运行。

要启用 GIPK,您必须设置以下动态系统变量(它具有全局和会话作用域):

mysql> SET [PERSIST] sql_generate_invisible_primary_key=ON; 

现在在不指定显式主键的情况下创建一个表:

mysql> CREATE TABLE customer(name VARCHAR(50));
Query OK, 0 rows affected (0.03 sec)

检查模式:

mysql> SHOW CREATE TABLE customerG
*************************** 1. row ***************************
  Table: customer  
Create Table: CREATE TABLE `customer` (
  `my_row_id` bigint unsigned NOT NULL AUTO_INCREMENT /*!80023 INVISIBLE */,
  `name` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`my_row_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
名为my_row_id的隐藏主键已经自动创建。

注意:

GIPK 的名称始终为my_row_id。您不能在表中有相同名称的列。

GIPK 的数据类型始终为使用 AUTO_INCREMENT 的 BIGINT UNSIGNED。

有趣的是,您可以在查询中使用主键并在明确寻址时看到它,就像描述的隐藏列一样。

mysql> INSERT INTO customer VALUES('Tim'),('Rob'),('Bob');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0

mysql> SELECT my_row_id, name FROM customer;
+--------------+-------+
| my_row_id | name |
+--------------+-------+
|         1 |  Tim |
|         2 |  Rob |
|         3 |  Bob |
+--------------+-------+
3 rows in set (0.00 sec)

mysql> SELECT my_row_id, name FROM customer WHERE my_row_id=2;
+--------------+-------+
| my_row_id | name |
+--------------+-------+
|         2 |  Rob |
+--------------+-------+
1 row in set (0.00 sec)
很显然。如果您执行SELECT *,主键不会被返回:
mysql> SELECT * FROM customer WHERE my_row_id=2;
+-------+
| name |
+-------+
| Rob  |
+-------+

在某些时候,您最终可以决定使其可见,并在需要时更改名称:

mysql> ALTER TABLE customer MODIFY `my_row_id` bigint unsigned not null auto_increment VISIBLE;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SHOW CREATE TABLE customerG  
*************************** 1. row ***************************
  Table: customer
Create Table: CREATE TABLE `customer` (
  `my_row_id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`my_row_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

隐藏索引

为了完成隐形事物的概述,我们也来讨论一下隐藏索引。这是最古老的隐形特性,在 MySQL 8.0 的第一个版本中就引入了。

您可以使索引对优化器不可见,以便测试如果该索引不存在,查询的性能会如何。

不过,当索引不可见时,在针对表执行任何 DML 语句(INSERT、UPDATE、DELETE、REPLACE)时,它仍会得到更新。

您可以使用以下语句将索引设置为不可见和再次可见:

ALTER TABLE mytable ALTER INDEX my_idx INVISIBLE;
ALTER TABLE mytable ALTER INDEX my_idx VISIBLE;
隐藏索引可以测试在不考虑它的情况下查询的执行计划。最大的优点是您不需要删除索引。请记住,索引删除几乎是瞬间完成的,但重建索引则不然。

根据表的大小,重建索引可能需要大量时间并过载服务器。另一种选择是,您也可以使用IGNORE INDEX()索引提示,但在这种情况下,您可能会被迫在应用程序代码中的许多查询上添加索引提示。

将索引设置为不可见将允许您在很短的时间内开始测试查询。并且您可以随时轻松地将其设置回可见,而不会丢失任何更新。

注意:

主键(PRIMARY Key)不能隐藏

UNIQUE 索引可以隐藏,但仍会执行唯一性检查

有关索引不可见性的信息在information_schema中可用

索引不可见性会被正确复制

总结

从我的角度来看,你不应该使用隐藏列,因为最佳实践是不应在任何应用中部署SELECT *查询。不过,在某些紧急情况下,此功能可能非常有用,可以飞快地解决问题。

但是之后要记住修复你的代码并将隐藏列设置为可见会更好。 对 GIPK 来说,情况也差不多。只要记住为表提供显式主键,就不需要此功能。

不过,它可以帮助一个创建时没有主键的表拥有一个适当的主键,这个主键可以方便地被使用和变得可见。

关于隐藏索引,这是一个非常简单的功能,在测试时非常有用,特别是在可能使用多个索引,和不确定优化器是否选择了最佳执行计划的情况中。






审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • MySQL
    +关注

    关注

    1

    文章

    776

    浏览量

    26102
  • DDL
    DDL
    +关注

    关注

    0

    文章

    11

    浏览量

    6294
  • 电源优化器
    +关注

    关注

    0

    文章

    11

    浏览量

    5396
  • MYSQL数据库
    +关注

    关注

    0

    文章

    95

    浏览量

    9297

原文标题:那些MySQL 8.0中的隐藏特性

文章出处:【微信号:OSC开源社区,微信公众号:OSC开源社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    EMC设计之——被动元件的隐藏特性

    EMC设计之——被动元件的隐藏特性
    发表于 10-23 17:03

    MySQL8.0特性:Partial Update of LOB Column

    摘要: MySQL8.0对json进行了比较完善的支持, 我们知道json具有比较特殊的存储格式,通常存在多个key value键值对,对于类似更新操作通常不会更新整个json列,而是某些键值
    发表于 06-11 20:23

    【鲁班猫门禁系统】安装并测试mysql

    mysql-client-8.0 mysql-client-core-8.0 mysql-common mysql-server-8.0 mysq
    发表于 04-26 20:35

    应用傅氏算法的几个问题讨论

    应用傅氏算法的几个问题讨论 傅氏算法在数字保护中得到了广泛的应用,但关于傅氏算法中余弦正弦系数a,b是否是信号相量的实部和虚部,作者一
    发表于 07-20 12:11 1880次阅读
    应用傅氏算法的<b class='flag-5'>几个</b>问题<b class='flag-5'>讨论</b>

    关于ThinkPad隐藏分区几个必知细节

    关于ThinkPad隐藏分区几个必知细节 1. 什么是隐藏分区   IBM没有提供随机的恢复光盘或者操作系统安装光盘,操作系统、随机软件、设
    发表于 01-22 12:07 1191次阅读

    MySQL5新特性之存储过程

    MySQL5新特性之存储过程 MySQL5新特性之存储过程 MySQL5新特性之存储过程
    发表于 06-12 10:08 0次下载

    腾讯云打造MySQL 8.0全新引擎,进一步加速客户产业升级

    据介绍,腾讯云数据库 MySQL 8.0的内核可以百分百完全兼容主流MySQL分支。相比官方版本,无论是单机模式、异步模式还是同步模式下, MySQL
    的头像 发表于 07-09 14:54 2221次阅读

    MySQL 5.7与MySQL 8.0 性能对比

    背景 测试mysql5.7和mysql8.0分别在读写,选定,只写模式下不同并发时的性能(tps,qps) 最早 测试使用版本为mysql5.7.22和mysql8.0.15 sysb
    的头像 发表于 11-03 09:26 1.4w次阅读
    <b class='flag-5'>MySQL</b> 5.7与<b class='flag-5'>MySQL</b> <b class='flag-5'>8.0</b> 性能对比

    MySql环境一键安装应用程序免费下载

    本文档的主要内容详细介绍的是MySql环境一键安装应用程序免费下载。创建Mysql所需环境支持8.0以上版本,暂无测试过8.0以下版本
    发表于 02-26 15:01 7次下载

    MySQL超级复杂?分享几个使用技巧

    MySQL是最知名的关系数据库管理系统,作为LAMP Web开发平台,此开源解决方案在全球广受欢迎。然而,它的流行并不意味着每个使用者都能从MySQL中获得最大收益,因为缺乏使用方法,它可
    发表于 01-19 16:53 589次阅读

    关于MySQL8.0版本选型的小技巧

    MySQL 8.0 第一个GA(General Availability)版本(正式、可用于生产的版本)于2018/4/19发布至今已有3年。8.0是一个全新的版本,增加了数百项功能新特性
    的头像 发表于 03-29 13:45 917次阅读
    关于<b class='flag-5'>MySQL8.0</b>版本选型的小技巧

    请问mysql8.0不能在grant时创建用户是什么原因?

    用习惯了MySQL5.7,当在MySQL8.0里创建用户时,习惯性直接敲GRANT指令,结果报错了
    的头像 发表于 08-11 10:16 1545次阅读

    mysql8.0默认字符集是什么

    MySQL 8.0 默认字符集是 utf8mb4。 MySQL 8.0 是当前最新的开源关系型数据库管理系统,由Oracle公司开发和维护。MySQ
    的头像 发表于 11-16 14:48 1407次阅读

    MySQL5.7数据导入8.0版本,这3款工具值得收藏!

    MySQL 5.7数据库迁移到MySQL 8.0可以使用NineData、MySQL Shell、Percona XtraBackup和Liquibase等工具。每个工具都有自己的优
    的头像 发表于 11-29 16:47 720次阅读
    <b class='flag-5'>MySQL</b>5.7数据导入<b class='flag-5'>8.0</b>版本,这3款工具值得收藏!

    GitHub底层数据库无缝升级到MySQL 8.0的经验

    GitHub 团队近日分享了他们将 GitHub.com 的底层数据库无缝升级到 MySQL 8.0 的经验。 据介绍,GitHub 使用 MySQL 来存储大量关系数据,因此在不影响网站服务级别
    的头像 发表于 12-13 10:21 307次阅读
    GitHub底层数据库无缝升级到<b class='flag-5'>MySQL</b> <b class='flag-5'>8.0</b>的经验