MySQL 8.0的新特性
MySQL 5.7 已经停止更新。官方的 EOL(End of Life,生命周期终止)日期是 2023 年 10 月 21 日,这意味着 Oracle 已不再提供任何安全补丁、错误修复或官方支持。MySQL 8.0 相比 5.7 版本带来了一些新特性和优化。
首先,我们来看看几个新特性:
Common Table Expression
公用表表达式:Common Table Expression,CTE。它可以让 SQL 语句的结构更加清晰,特别是在需要多次使用相同逻辑的查询时,可以避免嵌套子查询导致的可读性差的问题。
sqlWITH recent_orders AS ( SELECT customer_id, total_amount FROM orders WHERE order_date > NOW() - INTERVAL 7 DAY )
上面代码中,使用了 WITH 关键字来定义一个 CTE,它的作用类似于一个临时的查询结果集,可以在后续的 SELECT 语句中使用。这样,后续就可以使用:
sqlSELECT * FROM recent_orders;
来查询这个结果集中的内容。
相比子查询方式,如果查询逻辑较复杂,可以优先考虑 CTE,因为CTE可以让 SQL 更易读、易容易维护。
窗口函数
相比传统的 GROUP BY
方式,窗口函数使 MySQL 8.0 能够执行更强大的数据分析,提高了查询的灵活性和性能。来看一个例子:
在 employees 表中已经有如上数据,现在需要按照部门对每个员工按照薪资进行降序排序,可以使用窗口函数:
sqlSELECT id, name, department, salary, ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS `rank` FROM employees;
得到结果如下:
如果不使用窗口函数,需要用变量的方式:
sqlSET @rank = 0; SET @dept = ''; SELECT id, name, department, salary, `rank` FROM ( SELECT id, name, department, salary, @rank := IF(@dept = department, @rank + 1, 1) AS `rank`, @dept := department FROM employees ORDER BY department, salary DESC ) t;
导致查询更复杂、更低效,特别是涉及到跨行计算时。窗口函数在 MySQL 8.0 中更简洁高效,能大幅简化 SQL 语句。
降序索引
在 MySQL 5.7 及之前,索引默认是升序(ASC),即使你在 ORDER BY column DESC
进行查询,索引仍然是升序存储,查询时需要额外的排序操作。
在 MySQL 8.0 及以上版本中,降序索引(Descending Index)
允许索引按照降序(DESC) 排序,以提高查询效率。
来看一个简单例子:
sqlCREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(50), age INT ); -- 创建降序索引 CREATE INDEX idx_age_desc ON users (age DESC);
我们创建了一个表users,并且给 age 字段加了一个降序索引。插入一点数据:
sqlINSERT INTO users (id, name, age) VALUES (1, 'Alice', 25), (2, 'Bob', 30), (3, 'Charlie', 20);
然后,使用降序索引的查询:
sqlEXPLAIN SELECT age FROM users ORDER BY age DESC;
结果如下:
可以看到,在查询时,默认使用了这个降序索引。
隐藏索引
MySQL 8.0 引入了 隐藏索引(Invisible Index)
的概念。一个隐藏索引在数据库优化器中不可见,也就是说,查询优化器不会使用该索引,但索引数据仍然会被维护(插入、更新、删除数据时仍会更新索引)。
这个特性能够方便我们测试索引对查询性能的影响。
比如,我们可以先隐藏索引,观察查询性能是否受影响。如果没有影响,可以删除索引;如果有影响,可以恢复索引的可见性,而无需重新创建索引。
假设 users 表的 age 字段有一个索引:
sqlCREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(50), age INT, email VARCHAR(100), INDEX idx_age (age) -- 创建 age 列的索引 );
我们可以将其设置为隐藏索引:
sqlALTER TABLE users ALTER INDEX idx_age INVISIBLE;
此时,索引 idx_age 对查询优化器不可见,查询不会使用该索引。
如果发现查询性能下降,可以恢复索引:
sqlALTER TABLE users ALTER INDEX idx_age VISIBLE;
idx_age
又会被查询优化器使用。
通过隐藏索引可以安全地管理索引,避免盲目删除重要索引导致的查询性能下降。
性能优化
除了提供一些新特性外,mysql 8.0还针对性能做了一些优化。在高并发、大数据处理、JSON处理上, MySQL 8.0做了大量优化,提升了整体性能。
但具体到底提升了多少呢?有网友在硬件参数相同的情况下进行了基准测试:
bashvCPUS: 4 内存:16G
并且,为这个基准测试设置了几个值得注意的变量:
bashinnodb_max_dirty_pages_pct = 90 #脏页百分比,90为默认值 innodb_flush_neighbors=0 #关闭刷新邻接页功能开启 innodb_buffer_pool_instances=8 #新数据库缓冲池实例=8 innodb_buffer_pool_size=8GiB #新数据库缓冲池大小=8GiB
两个 MySQL具体版本为:
bash
MySQL 5.7版本:MySQL社区服务器 - GPL 5.7.24 MySQL 8.0版本:MySQL社区服务器 - GPL 8.0.14
MySQL 5.7 和 MySQL 8.0 这两个节点都处于休眠状态,没有活动连接经过这些节点,因此它本质上是一个纯粹的基准测试。得到的读取速度对比图如下:
可以看到,在线程数量大于512后,mysql8.0的读取速度明显高于mysql5.7。这表明,8.0版本在高并发场景下会有更好的表现。