摘要:MySQL 8.0 是 MySQL 历史上最重要的版本升级之一,带来了性能、安全、开发效率的全方位提升。本文精选 10 大核心新特性:窗口函数、CTE 公用表表达式、降序索引、不可见索引、原子 DDL、角色权限管理、JSON 增强、直方图统计、默认字符集升级、以及全新的 MySQL Shell。每个特性都配有实战示例,帮你快速上手 MySQL 8.0。
一、MySQL 8.0 概览:为什么值得升级?
MySQL 8.0 于 2018 年 4 月发布 GA 版本,是时隔 4 年的重大升级(上一版 5.7 发布于 2015 年)。官方宣称性能提升2 倍,并引入了 100+ 项新特性。
上图展示了 MySQL 8.0 的核心架构:不仅支持传统的关系型表(Relational Tables),还通过 X Protocol 原生支持 JSON 文档存储(JSON Collections),实现 SQL + NoSQL 双模能力。
升级前的注意事项:
- MySQL 8.0 要求数据字典升级,不支持直接从 5.5/5.6 升级,必须先升级到 5.7
- 默认认证插件从
mysql_native_password改为caching_sha2_password,旧客户端可能连不上 - 部分废弃特性已移除(如
query_cache、mysql_install_db)
二、特性 1:窗口函数(Window Functions)
2.1 什么是窗口函数?
窗口函数是 SQL 2003 标准的一部分,MySQL 8.0 终于补齐了这个短板。它可以在不改变行数的情况下,对一组相关的行进行计算。
与传统聚合函数的区别:
| 特性 | 聚合函数(GROUP BY) | 窗口函数 |
|---|---|---|
| 输出行数 | 每组一行(压缩) | 每行都保留 |
| 计算范围 | 整组数据 | 滑动窗口(可自定义范围) |
| 典型用途 | 汇总统计 | 排名、累计、移动平均 |
2.2 常用窗口函数
-- 假设表结构CREATETABLEsales(idINTPRIMARYKEY,productVARCHAR(50),regionVARCHAR(50),amountDECIMAL(18,2),sale_dateDATE);-- 1. ROW_NUMBER():为每组内的行分配唯一序号SELECTproduct,region,amount,ROW_NUMBER()OVER(PARTITIONBYregionORDERBYamountDESC)ASrank_in_regionFROMsales;-- 结果:每个 region 内按 amount 降序排名,1, 2, 3...-- 2. RANK() / DENSE_RANK():排名(允许并列)SELECTproduct,amount,RANK()OVER(ORDERBYamountDESC)ASrank,-- 并列跳号:1, 1, 3DENSE_RANK()OVER(ORDERBYamountDESC)ASdense_rank-- 并列不跳号:1, 1, 2FROMsales;-- 3. LAG() / LEAD():访问前/后行的数据SELECTproduct,amount,LAG(amount,1)OVER(ORDERBYsale_date)ASprev_amount,-- 上一行的 amountLEAD(amount,1)OVER(ORDERBYsale_date)ASnext_amount-- 下一行的 amountFROMsales;-- 4. SUM() OVER:累计求和SELECTsale_date,amount,SUM(amount)OVER(ORDERBYsale_date)AScumulative_sum,-- 从第一行累加到当前行SUM(amount)OVER(ORDERBYsale_dateROWSBETWEEN6PRECEDINGANDCURRENTROW)ASmoving_7dFROMsales;-- 5. NTILE():将数据分为 N 组(分位数)SELECTproduct,amount,NTILE(4)OVER(ORDERBYamountDESC)ASquartile-- 按 amount 分为 4 组FROMsales;2.3 窗口函数实战:TOP N 问题
-- 问题:找出每个区域销售额 TOP 3 的产品-- MySQL 5.7 的笨办法:子查询 + 变量-- MySQL 8.0 的优雅写法:SELECT*FROM(SELECTproduct,region,amount,ROW_NUMBER()OVER(PARTITIONBYregionORDERBYamountDESC)ASrnFROMsales)tWHERErn<=3;三、特性 2:CTE 公用表表达式(Common Table Expressions)
3.1 普通 CTE
CTE 允许定义临时结果集,在后续 SELECT 中多次引用,使复杂查询更易读。
-- 定义 CTEWITHregional_salesAS(SELECTregion,SUM(amount)AStotal_salesFROMsalesGROUPBYregion),top_regionsAS(SELECTregionFROMregional_salesORDERBYtotal_salesDESCLIMIT3)-- 使用 CTESELECTs.product,s.region,s.amountFROMsales sJOINtop_regions trONs.region=tr.region;3.2 递归 CTE
递归 CTE 可以处理树形结构数据(如组织架构、分类层级)。
-- 员工表(id, name, manager_id)CREATETABLEemployees(idINTPRIMARYKEY,nameVARCHAR(50),manager_idINT,FOREIGNKEY(manager_id)REFERENCESemployees(id));-- 查询某个员工的所有下属(递归)WITHRECURSIVE subordinatesAS(-- 锚成员:找到起始员工SELECTid,name,manager_id,0ASlevelFROMemployeesWHEREid=1-- CEOUNIONALL-- 递归成员:找到下属的下属SELECTe.id,e.name,e.manager_id,s.level+1FROMemployees eJOINsubordinates sONe.manager_id=s.id)SELECT*FROMsubordinatesORDERBYlevel,id;四、特性 3:降序索引(Descending Indexes)
4.1 为什么需要降序索引?
在 MySQL 5.7 中,虽然可以创建DESC索引,但内部实际还是升序存储,只是反向扫描。当查询同时包含升序和降序排序时,优化器无法完全利用索引。
上图展示了 MySQL 8.0 降序索引在 ORDER BY 混合排序场景下的性能提升:对于(a DESC, b ASC)这类混合排序查询,8.0 的耗时显著低于 5.7。
4.2 创建降序索引
-- MySQL 8.0 真正支持降序存储CREATEINDEXidx_amount_dateONsales(amountDESC,sale_dateASC);-- 查询可以直接利用索引,无需 filesortSELECT*FROMsalesORDERBYamountDESC,sale_dateASC;-- Extra: Using index(而不是 Using filesort)五、特性 4:不可见索引(Invisible Indexes)
5.1 用途
DBA 可以临时将索引设为"不可见",优化器会忽略它,但索引仍在后台维护。用于安全地测试删除索引的影响。
-- 创建不可见索引CREATEINDEXidx_testONsales(product)INVISIBLE;-- 或将现有索引设为不可见ALTERTABLEsalesALTERINDEXidx_product INVISIBLE;-- 测试查询性能(优化器不会使用该索引)EXPLAINSELECT*FROMsalesWHEREproduct='iPhone';-- 如果性能下降,随时恢复可见ALTERTABLEsalesALTERINDEXidx_product VISIBLE;5.2 强制使用不可见索引
-- 会话级别强制优化器考虑不可见索引SETSESSIONoptimizer_switch='use_invisible_indexes=on';六、特性 5:原子 DDL(Atomic DDL)
6.1 什么是原子 DDL?
MySQL 8.0 将 DDL 操作(如 CREATE、ALTER、DROP)变为原子性操作:要么完全成功,要么完全回滚,不会出现"操作一半失败导致数据字典不一致"的情况。
-- MySQL 5.7 的问题:DROP TABLE 中途崩溃,可能表文件删了但数据字典记录还在-- MySQL 8.0 的解决:DROP TABLE 是原子操作,失败会自动回滚-- 示例:安全地重命名表RENAMETABLEold_tableTOnew_table;-- 原子操作,不会半成功6.2 INSTANT ADD COLUMN
MySQL 8.0.12+ 支持瞬间加列,无需复制整张表数据。
-- 传统加列(MySQL 5.7):复制整张表,大表可能需要数小时ALTERTABLEbig_tableADDCOLUMNnew_colVARCHAR(50);-- 耗时取决于表大小-- MySQL 8.0 INSTANT 加列:修改元数据,毫秒级完成ALTERTABLEbig_tableADDCOLUMNnew_colVARCHAR(50),ALGORITHM=INSTANT;-- 限制:只能加在表尾,不能加在中间(8.0.29+ 支持加在中间)-- 查看表是否支持 INSTANTSELECTNAME,TOTAL_ROW_VERSIONS,CASEWHENTOTAL_ROW_VERSIONS>0THEN'支持 INSTANT'ELSE'不支持'ENDASinstant_supportFROMinformation_schema.INNODB_TABLESWHERENAME='db1/big_table';七、特性 6:角色权限管理(Roles)
7.1 创建和使用角色
MySQL 8.0 引入了角色(Role)概念,可以批量管理权限,类似 Linux 的用户组。
-- 创建角色CREATEROLE'app_read','app_write','app_admin';-- 给角色授权GRANTSELECTONmydb.*TO'app_read';GRANTSELECT,INSERT,UPDATE,DELETEONmydb.*TO'app_write';GRANTALLPRIVILEGESONmydb.*TO'app_admin';-- 创建用户并赋予角色CREATEUSER'developer'@'%'IDENTIFIEDBY'password';GRANT'app_write'TO'developer'@'%';-- 创建用户并赋予多个角色CREATEUSER'dba'@'%'IDENTIFIEDBY'password';GRANT'app_read','app_write','app_admin'TO'dba'@'%';-- 用户激活角色(默认不自动激活)SETDEFAULTROLE'app_write'TO'developer'@'%';-- 或用户登录后手动激活SETROLE'app_write';-- 查看当前用户的角色和权限SHOWGRANTS;SHOWGRANTSFORCURRENT_ROLE();7.2 强制角色(Mandatory Roles)
# my.cnf:所有用户自动拥有某些角色 [mysqld] mandatory_roles = 'app_read'八、特性 7:JSON 增强
8.1 JSON 数据类型改进
MySQL 5.7 已支持 JSON,8.0 进一步增强了 JSON 操作能力。
-- 创建 JSON 列CREATETABLEusers(idINTPRIMARYKEY,profile JSON,INDEXidx_city((CAST(profile->>'$.city'ASCHAR(50))))-- 函数索引(8.0.13+));-- 插入 JSON 数据INSERTINTOusersVALUES(1,'{"name": "张三", "age": 25, "city": "北京", "tags": ["程序员", "篮球"]}');-- JSON 路径查询SELECTid,JSON_EXTRACT(profile,'$.name')ASname,profile->>'$.city'AScity,-- ->> 是 JSON_EXTRACT + UNQUOTE 的简写JSON_CONTAINS(profile,'"篮球"','$.tags')ASlikes_basketballFROMusers;-- JSON 聚合函数SELECTid,JSON_ARRAYAGG(tag)ASall_tags-- 将多行聚合成 JSON 数组FROMuser_tagsGROUPBYid;-- JSON 表函数(将 JSON 数组展开为多行)SELECTu.id,jt.tagFROMusers u,JSON_TABLE(u.profile,'$.tags[*]'COLUMNS(tagVARCHAR(50)PATH'$'))ASjt;8.2 多值索引(Multi-Valued Indexes)
MySQL 8.0.17+ 支持对 JSON 数组创建索引。
-- 为 JSON 数组创建多值索引CREATEINDEXidx_tagsONusers((CAST(profile->>'$.tags'ASCHAR(50)ARRAY)));-- 查询可以利用索引SELECT*FROMusersWHEREJSON_CONTAINS(profile,'"篮球"','$.tags');九、特性 8:直方图统计(Histograms)
9.1 为什么需要直方图?
优化器依赖索引统计信息(如 cardinality)来估算查询成本。但对于数据分布不均的列(如 80% 是 “completed”,20% 是 “pending”),简单的 cardinality 无法准确反映分布情况,导致优化器选择错误的执行计划。
上图展示了直方图如何将数据分布划分为多个桶(bucket),每个桶记录值的频率,帮助优化器更准确地估算查询成本。
9.2 创建和使用直方图
-- 为 status 列创建直方图(默认 100 个桶)ANALYZETABLEordersUPDATEHISTOGRAMONstatusWITH100BUCKETS;-- 查看直方图信息SELECTCOLUMN_NAME,HISTOGRAM->>'$."number-of-buckets-specified"'ASbuckets,HISTOGRAM->>'$."data-type"'ASdata_typeFROMinformation_schema.COLUMN_STATISTICSWHERETABLE_NAME='orders'ANDCOLUMN_NAME='status';-- 删除直方图ANALYZETABLEordersDROPHISTOGRAMONstatus;-- 查看优化器是否使用了直方图EXPLAINANALYZESELECT*FROMordersWHEREstatus='pending';-- 如果 rows 估算更准确,说明直方图生效十、特性 9:默认字符集升级
10.1 utf8mb4 成为默认字符集
MySQL 8.0 将默认字符集从latin1升级为utf8mb4,排序规则升级为utf8mb4_0900_ai_ci。
| 版本 | 默认字符集 | 默认排序规则 | 说明 |
|---|---|---|---|
| MySQL 5.7 | latin1 | latin1_swedish_ci | 不支持 Emoji |
| MySQL 8.0 | utf8mb4 | utf8mb4_0900_ai_ci | 支持 Emoji、中文、多语言 |
-- 查看默认字符集SHOWVARIABLESLIKE'character_set%';-- 创建表时显式指定(推荐)CREATETABLEcomments(idINTPRIMARYKEY,contentVARCHAR(500))CHARACTERSETutf8mb4COLLATEutf8mb4_unicode_ci;-- 旧表升级到 utf8mb4ALTERTABLEold_tableCONVERTTOCHARACTERSETutf8mb4COLLATEutf8mb4_unicode_ci;注意:utf8mb4_0900_ai_ci是 MySQL 8.0 新增的排序规则,基于 Unicode 9.0,比utf8mb4_general_ci更准确,但部分旧系统可能不兼容。
十一、特性 10:MySQL Shell 与 X Protocol
11.1 MySQL Shell:新一代客户端
MySQL Shell 是官方推出的高级客户端,支持 JavaScript、Python 和 SQL 三种模式。
# 启动 MySQL Shellmysqlsh root@localhost:3306# JavaScript 模式(默认)\js# 执行 SQL\sql SELECT * FROMusersWHEREid=1;# 执行 JavaScript 脚本db=session.getSchema('mydb');table=db.getTable('users');result=table.select(['id','name']).where('age > 18').execute();print(result.fetchAll());# 使用 AdminAPI 管理 MGR 集群\js cluster=dba.createCluster('myCluster');cluster.addInstance('root@db2:3306');cluster.addInstance('root@db3:3306');cluster.status();11.2 X Protocol 与 Document Store
MySQL 8.0 通过 X Plugin 支持 X Protocol,可以直接操作 JSON 文档,无需 SQL。
// MySQL Shell 中使用 Document Store\js session=mysqlx.getSession('root:password@localhost:33060');db=session.getSchema('mydb');// 创建集合(类似 MongoDB 的 Collection)collection=db.createCollection('products');// 插入文档collection.add({name:'iPhone 15',price:5999,tags:['手机','苹果']}).execute();// 查询文档result=collection.find('price > 5000').execute();print(result.fetchAll());// 修改文档collection.modify('name = "iPhone 15"').set('price',5799).execute();十二、其他值得关注的特性
| 特性 | 版本 | 说明 |
|---|---|---|
| 持久化配置 | 8.0 | SET PERSIST将变量修改持久化到mysqld-auto.cnf,重启后仍生效 |
| 资源组(Resource Groups) | 8.0 | 限制线程的 CPU 和 IO 使用,隔离不同业务的资源 |
| 倒排索引 | 8.0.13+ | InnoDB 表支持全文倒排索引,提升全文检索性能 |
| 克隆插件(Clone Plugin) | 8.0.17+ | 快速物理克隆实例,用于搭建从库或备份 |
| 备份锁(Backup Lock) | 8.0 | LOCK INSTANCE FOR BACKUP允许在线备份时阻塞 DDL,不阻塞 DML |
| TempTable 引擎 | 8.0 | 替代 Memory 引擎处理内部临时表,支持变长数据类型 |
十三、升级 checklist
□ 确认当前版本:必须是 5.7(不支持 5.5/5.6 直接升级) □ 备份数据:mysqldump 或物理备份(XtraBackup) □ 检查废弃特性:移除 query_cache、mysql_install_db 等 □ 检查认证插件:旧客户端需升级或改为 mysql_native_password □ 检查 SQL 模式:ONLY_FULL_GROUP_BY 等模式更严格 □ 测试环境验证:先在测试库跑一遍升级流程 □ 检查性能:关键查询用 EXPLAIN 对比执行计划 □ 检查字符集:确认 utf8mb4 兼容性 □ 监控升级过程:观察错误日志和性能指标十四、面试高频考点速记
Q1:MySQL 8.0 相比 5.7 有哪些重要改进?
- 窗口函数和 CTE 补齐 SQL 标准;
- 降序索引和不可见索引优化查询性能;
- 原子 DDL 避免数据字典不一致;
- 角色权限管理简化权限控制;
- JSON 增强和多值索引支持文档存储;
- 直方图统计优化查询计划;
- 默认 utf8mb4 支持 Emoji;
- MySQL Shell 和 X Protocol 提供 NoSQL 能力。
Q2:窗口函数和 GROUP BY 有什么区别?
GROUP BY 将多行聚合成一行(压缩),窗口函数保留所有行,在每行上计算聚合值。窗口函数通过 OVER 子句定义计算范围(PARTITION BY 分组 + ORDER BY 排序 + ROWS/RANGE 滑动窗口)。
Q3:什么是原子 DDL?有什么好处?
MySQL 8.0 将 DDL 操作变为原子性:要么完全成功,要么完全回滚。好处是避免操作中途崩溃导致数据字典和文件系统不一致(如表文件删了但字典记录还在)。同时支持 INSTANT ADD COLUMN,大表加列从小时级降到毫秒级。
Q4:MySQL 8.0 的默认认证插件是什么?旧客户端连不上怎么办?
默认改为
caching_sha2_password,比mysql_native_password更安全但兼容性差。解决方法:1. 升级客户端驱动;2. 创建用户时显式指定WITH mysql_native_password;3. 修改全局变量default_authentication_plugin。
Q5:不可见索引有什么用途?
允许 DBA 临时禁用索引而不删除它,用于安全地测试删除索引对查询性能的影响。如果性能下降,随时恢复可见,无需重新创建索引。
Q6:MySQL 8.0 的 JSON 多值索引是什么?
允许对 JSON 数组类型的字段创建索引。例如用户标签是 JSON 数组
["程序员", "篮球"],可以创建多值索引让JSON_CONTAINS查询走索引,而不是全表扫描。
结语
MySQL 8.0 是一次全面的现代化升级:
- 开发效率:窗口函数、CTE、JSON 增强让复杂查询更简洁
- 运维安全:原子 DDL、不可见索引、角色管理降低运维风险
- 性能优化:降序索引、直方图、TempTable 引擎提升查询效率
- 架构扩展:MGR、Clone Plugin、MySQL Shell 支持云原生和分布式场景
如果你还在用 MySQL 5.7,强烈建议制定升级计划。MySQL 5.7 已于2023 年 10 月停止官方支持,不再接收安全补丁。
如果本文对你有帮助,欢迎点赞收藏+关注!