本文介绍MySQL 8的主要新特性及移除的旧特性,详解核心功能的定义、用法与示例。
算是作为SQL基础篇的最后一篇补充。
本文的内容可作为一个内容补充,
基本知识在前15篇中都覆盖到了,这次只是介绍MySQL8的一些新特性。
如果不是很深入,只是日常普通运用的话,
5.7版本基本上也够用。
MySQL 8在功能上有显著改进,重构了源代码,优化了优化器,提升了性能与用户体验,同时移除了部分旧特性。
JSON_ARRAYAGG()
、JSON_OBJECTAGG()
聚合函数,增强->>
操作符,优化JSON排序与更新。caching_sha2_password
插件、角色管理、密码历史记录等,提升安全性。latin1
改为utf8mb4
,新增日语特定字符集utf8mb4_ja_0900_as_cs
。WITH
语句命名临时结果集,简化复杂查询。REGEXP_LIKE()
等函数,支持资源消耗控制。TempTable
引擎替代MEMORY
成为默认引擎,高效存储VARCHAR
等类型。log_error_services
配置过滤与写入。FLUSH QUERY CACHE
)、系统变量(如query_cache_size
)等。ENCODE()
、DES_ENCRYPT()
等,建议用SHA2()
、AES_ENCRYPT()
替代。ST_
和MBR
前缀的空间函数。\N
与NULL
:SQL解析器不再将\N
视为NULL
,需用NULL
替代(LOAD DATA
等操作除外)。mysql_install_db
:移除该程序,数据字典初始化通过mysqld --initialize
实现。INFORMATION_SCHEMA
中GLOBAL_VARIABLES
等表,改用性能模式替代。mysql_plugin
工具:通过--plugin-load
或INSTALL PLUGIN
替代。窗口函数用于在查询中对分组数据进行统计,同时保留原表行数,避免传统分组统计丢失细节的问题。
传统方法需通过临时表分步计算分组统计(如计算各区销售额占比),步骤繁琐;窗口函数可直接在一行中完成分组统计与占比计算,高效简洁。
示例:计算各区销售额占城市与全国总额的比例
SELECT
city AS 城市,
county AS 区,
sales_value AS 区销售额,
SUM(sales_value) OVER(PARTITION BY city) AS 市销售额, -- 按城市分组统计
sales_value/SUM(sales_value) OVER(PARTITION BY city) AS 市比率,
SUM(sales_value) OVER() AS 总销售额, -- 全局统计
sales_value/SUM(sales_value) OVER() AS 总比率
FROM sales
ORDER BY city, county;
分类 | 函数 | 说明 |
---|---|---|
序号函数 | ROW_NUMBER() |
顺序排序,序号唯一 |
RANK() |
并列排序,跳过重复序号(如1,1,3) | |
DENSE_RANK() |
并列排序,不跳过重复序号(如1,1,2) | |
分布函数 | PERCENT_RANK() |
计算等级百分比:(rank-1)/(总行数-1) |
CUME_DIST() |
计算小于等于当前值的比例 | |
前后函数 | LAG(expr, n) |
返回当前行前n行的expr 值 |
LEAD(expr, n) |
返回当前行后n行的expr 值 |
|
首尾函数 | FIRST_VALUE(expr) |
返回窗口首行的expr 值 |
LAST_VALUE(expr) |
返回窗口尾行的expr 值 |
|
其他函数 | NTH_VALUE(expr, n) |
返回第n行的expr 值 |
NTILE(n) |
将分区数据分为n组,返回组编号 |
-- 方式1:直接定义窗口
函数 OVER([PARTITION BY 字段 ORDER BY 字段 ASC|DESC])
-- 方式2:通过窗口名复用
函数 OVER 窗口名
...
WINDOW 窗口名 AS ([PARTITION BY 字段 ORDER BY 字段 ASC|DESC])
PARTITION BY
:按字段分组,每组独立计算。ORDER BY
:组内排序,影响序号类函数结果。以goods
表(含商品分类、价格等)为例:
ROW_NUMBER()
:查询每类商品价格降序的序号
SELECT
ROW_NUMBER() OVER(PARTITION BY category_id ORDER BY price DESC) AS row_num,
id, category, NAME, price
FROM goods;
RANK()
:查询每类商品价格排名(允许并列,跳过重复序号)
SELECT
RANK() OVER(PARTITION BY category_id ORDER BY price DESC) AS row_num,
id, category, NAME, price
FROM goods;
LAG()
:查询当前商品与前一个商品的价格差
SELECT
id, NAME, price,
LAG(price, 1) OVER(PARTITION BY category_id ORDER BY price) AS pre_price,
price - LAG(price, 1) OVER(PARTITION BY category_id ORDER BY price) AS diff
FROM goods;
CTE是命名的临时结果集,作用范围为当前语句,可替代子查询且支持复用,分为普通和递归两种。
WITH CTE名称 AS (子查询)
SELECT|DELETE|UPDATE 语句;
-- 定义CTE获取员工所属部门ID
WITH emp_dept_id AS (SELECT DISTINCT department_id FROM employees)
-- 关联部门表查询详情
SELECT d.*
FROM departments d
JOIN emp_dept_id e ON d.department_id = e.department_id;
WITH RECURSIVE CTE名称 AS (
种子查询 -- 初始数据集(仅执行一次)
UNION ALL
递归查询 -- 引用CTE自身,直至无新数据
)
SELECT|DELETE|UPDATE 语句;
WITH RECURSIVE cte AS (
-- 种子查询:初代管理者(如employee_id=100)
SELECT employee_id, last_name, manager_id, 1 AS n
FROM employees
WHERE employee_id = 100
UNION ALL
-- 递归查询:找出以CTE中人员为管理者的下属,代次+1
SELECT a.employee_id, a.last_name, a.manager_id, n+1
FROM employees a
JOIN cte ON a.manager_id = cte.employee_id
)
-- 筛选代次≥3的下下属
SELECT employee_id, last_name FROM cte WHERE n >= 3;
MySQL 8的新特性显著提升了数据库性能与开发效率。
窗口函数简化了分组统计与排序场景,避免临时表操作;
公用表表达式,尤其是递归CTE简化了复杂查询,支持树形结构数据处理。
同时,需注意移除的旧特性(如查询缓存),避免兼容性问题。
不过,在实际使用中,MySQL 5.7 和 8.0 对于多数基础业务场景差异不大!!
两者在常规的增删改查、事务处理等核心功能上表现相近,
对于中小型应用或对新特性需求不高的场景,5.7 完全能满足需求,
而 8.0 的新特性更多是为复杂场景和性能优化提供支持。