无论是做Java还是Python开发,数据库Mysql相信大家不陌生,可能你现在用的是5.7,或者8.0,8.4版本。今天主要和大家来好好聊聊 Mysql 9.7这个创新版本,还是很强大的 。
一、先聊聊 MySQL 这位老朋友
二、版本号一路狂飙:从 5.7 到 9.7
三、9 版本最亮的四张牌
3.1 VECTOR:数据库自己会"理解"语义了
3.2 JavaScript 存储程序:把逻辑搬进数据库
3.3 批量导入加速:大数据量入库不再靠熬夜
3.4 安全与可观测性:该扔的包袱扔掉了
四、实战:用 MySQL 9.7 做一个语义搜索
五、要不要升级?一张图帮你决定
如果把数据库世界比作一条街,MySQL 大概就是街口那家开了三十年的老店。
它 1995 年诞生,后来被 Sun 收购,Sun 又被 Oracle 收购,中间还分出了 MariaDB 这个"亲戚"。一路风波不断,但它始终是全世界用得最多的开源关系型数据库之一——从个人博客到淘宝早期的交易系统,从创业公司的第一张表到大厂的分库分表集群,背后多半都有它。
MySQL 受欢迎的原因其实挺朴素:
上手快 。装完就能用,
CREATE TABLE一敲,业务就能跑起来。生态厚 。Java、Go、Python、PHP,随便哪个语言,驱动、ORM、连接池、监控工具全都是现成的。
够稳 。InnoDB 引擎打磨了十几年,事务、MVCC、崩溃恢复这些硬功夫早就练扎实了。
但老店也有烦恼。这几年 AI 应用火起来,大家发现一个尴尬的事实: 业务数据在 MySQL 里,AI 需要的向量数据却得另外找地方放 。于是架构图上多了一个向量数据库,多了一套同步逻辑,多了一堆一致性问题。
MySQL 9 系列想解决的,就是这类"新时代的新麻烦"。
二、版本号一路狂飙:从 5.7 到 9.7
先说个容易让人困惑的事: MySQL 现在有两条发布通道 。
LTS(长期支持版) :比如 8.4,稳定为先,只修 bug 不加新功能,适合生产环境长期躺着跑。
Innovation(创新版) :9.0、9.1、9.2…… 一直到 9.7,几个月发一个,新特性优先上车,适合想尝鲜、想提前验证新能力的团队。
所以 9.7 并不是"比 8.4 高了一个大版本"那么简单,它更像是 MySQL 的"尝鲜频道"里目前最新的一集。功能最激进,但每个小版本的维护周期也短——新版本一出,上一个就不再收到补丁了。
![]()
一句话总结版本选择: 图求稳选 LTS,图新功能选 Innovation 。不用纠结数字大小。
三、9 版本最亮的四张牌 3.1 VECTOR:数据库自己会"理解"语义了
这是整个 9 系列最有分量的改动。MySQL 从 9.0 开始引入了原生的 VECTOR 数据类型,到 9.7 这条线已经打磨得相当顺手了。
所谓向量,就是把一段文字、一张图片丢给 AI 模型,模型返回一串浮点数(比如 768 个),这串数字代表了内容的"含义"。含义越接近的两段文字,它们的向量在空间里就越靠近。于是"搜索"这件事,从"匹配关键词"变成了"找最近的邻居"。
![]()
过去想在 MySQL 里干这事,只能把向量硬塞进 JSON 或 BLOB 字段,然后把所有数据捞到应用层算距离——数据量一大就直接崩了。现在可以这样写:
-- 创建库,utf8mb4 一步到位CREATE DATABASE db_ai_search DEFAULTCHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;USE db_ai_search;-- 文档表:业务字段和向量字段住在同一张表里CREATE TABLE t_doc (id BIGINTNOT AUTO_INCREMENT COMMENT '主键ID',title VARCHAR(200) NOT COMMENT '文档标题',content TEXT COMMENT '文档正文',embedding VECTOR(768) COMMENT '正文的向量表示,768维',create_time DATETIME NOT DEFAULTCURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (id)) ENGINE = InnoDB COMMENT ='文档表';
注意 VECTOR(768) 这个写法,括号里是维度,必须和你用的 embedding 模型输出维度对上(OpenAI 的 text-embedding-3-small 是 1536,BGE-base 是 768,按实际情况填)。
写入的时候,向量用字符串形式传进来,再用 STRING_TO_VECTOR 转换:
-- 写入一条文档(向量数值这里只做示意,真实场景由模型生成)INSERT INTO t_doc (title, content, embedding)VALUES ('MySQL 索引优化入门','本文介绍 B+ 树索引的结构,以及如何通过覆盖索引减少回表……',STRING_TO_VECTOR('[0.0123, -0.0456, 0.0789, ... ]'));-- 想看看某个向量存对了没有,可以反向转回字符串SELECT id, title, VECTOR_DIM(embedding) AS dim, create_timeFROM t_docWHERE id =1;
检索则是这样,把用户问题的向量传进去,按距离排序取最近的几条:
-- 语义搜索:找出和用户提问最接近的 5 篇文档SET@query_vec= STRING_TO_VECTOR('[0.0110, -0.0430, 0.0820, ... ]');SELECTid,title,DISTANCE(embedding, @query_vec, 'COSINE') AS score,DATE_FORMAT(create_time, '%Y-%m-%d %H:%i:%s') AS create_time_strFROM t_docORDERBY score ASC-- 距离越小,语义越接近LIMIT 5;
看到这里你大概能感受到它的价值了: 不需要额外部署向量数据库,业务数据和向量数据在同一个事务里,一次 SQL 就能完成"筛选 + 语义排序" 。比如"只在最近三个月的技术类文档里做语义搜索",加个 WHERE 就完事,这种混合查询恰恰是独立向量库最头疼的场景。
小提示:向量相关函数(尤其是距离计算和向量索引)在社区版与企业版、以及不同小版本之间存在差异,上线前务必对照你所用版本的官方 Release Notes 确认一遍。3.2 JavaScript 存储程序:把逻辑搬进数据库
用过 MySQL 存储过程的人都懂那种痛——它自带的 SQL 过程语言语法古老、调试困难、写个 JSON 解析能让人怀疑人生。
MySQL 9 系列支持用 JavaScript 写存储函数和存储过程,还能把公共代码抽成"库"( CREATE LIBRARY )供多处复用。
![]()
它真正解决的问题是 数据搬运成本 。举个典型场景:表里有个 JSON 字段存着订单明细,你要算每单的加权折扣。传统做法是把整行数据传到应用层,算完再写回去——十万行数据就是十万次来回。现在可以让计算发生在数据旁边:
-- 用 JavaScript 写一个订单折扣计算函数CREATEFUNCTIONfn_calc_discount(order_detail JSON)RETURNSDECIMAL(10, 2)LANGUAGEJAVASCRIPTAS $$// 解析订单明细,按商品类型分别计算折扣const items = JSON.parse(order_detail);let total = 0;for (const item of items) {const amount = item.price * item.qty;// 图书类打 8 折,数码类打 9.5 折,其余原价if (item.category === 'book') {total += amount * 0.8;} elseif (item.category === 'digital') {total += amount * 0.95;} else {total += amount;}}returnMath.round(total * 100) / 100;$$;
用起来和普通函数没区别:
SELECTorder_no,fn_calc_discount(detail_json) AS pay_amount,DATE_FORMAT(create_time, '%Y-%m-%d %H:%i:%s') AS create_time_strFROM t_orderWHERE create_time >='2026-09-01';
一条 SQL 搞定,省掉了 N 次网络往返。当然要提醒一句: 别把所有业务逻辑都塞进数据库 。它适合放那些"数据密集、逻辑稳定"的计算;频繁变动的业务规则还是留在应用层,否则发版和排错都会变成噩梦。另外,JavaScript 存储程序属于企业版能力,社区版用户需要留意这一点。
3.3 批量导入加速:大数据量入库不再靠熬夜
做过数据迁移的都知道,导入几亿行数据是个体力活。9 系列在这块做了明显优化:
支持直接从 URL / 对象存储 (如 S3)读取文件导入,不用先下载到本地磁盘再
LOAD DATA;支持 并行加载 ,多线程同时往 InnoDB 灌数据;
针对空表的批量插入,减少了中间的索引维护和日志开销。
-- 从对象存储直接批量导入(语法以实际版本文档为准)LOAD DATA FROM URL 's3://my-bucket/data/user_2026.csv'INTOTABLE t_userFIELDS TERMINATED BY','LINES TERMINATED BY'\n'IGNORE 1 LINES(user_name, nick_name, gender, create_time);
实测在千万级数据的场景下,这套组合拳能把导入时间压缩相当可观的比例——具体数字取决于磁盘、网络和表结构,但方向是明确的: 离线数据入库这件事,终于不那么折磨人了 。
3.4 安全与可观测性:该扔的包袱扔掉了
这部分不够炫,但对运维很实在。
彻底移除 mysql_native_password 。 这个上古认证插件从 9.0 开始被移除,默认认证方式是 caching_sha2_password 。好处是安全性提升,代价是老驱动可能直接连不上——升级前一定要检查客户端版本。
-- 检查当前所有账号用的认证插件,有没有漏网之鱼SELECTuser, host, pluginFROM mysql.userWHERE plugin <>'caching_sha2_password';-- 创建账号时显式指定(测试环境密码用 123456 仅作示例,生产请用强密码)CREATEUSER'app_user'@'%'IDENTIFIED WITH caching_sha2_password BY'123456';GRANTSELECT, INSERT, UPDATE, DELETEON db_ai_search.*TO'app_user'@'%';FLUSH PRIVILEGES;
EXPLAIN ANALYZE 结果可以存进变量了。 以前想把执行计划保存下来做分析,只能靠客户端抓输出再解析文本,现在可以直接落到变量里,做自动化性能巡检就方便多了:
四、实战:用 MySQL 9.7 做一个语义搜索-- 把执行计划以 JSON 形式塞进变量,后续可以直接入库存档EXPLAIN ANALYZE FORMAT = JSONINTO@planSELECT id, title FROM t_doc WHERE create_time >='2026-09-01';-- 取出来看看,或者写进你的慢查询分析表SELECT JSON_EXTRACT(@plan, '$.query_block.cost_info') AS cost_info;
光看语法没感觉,我们串一条完整链路:用户在搜索框输入一句话,返回语义最相关的文档。
![]()
对应的 Java 服务端代码大致是这样(不使用 Lombok,手写 getter/setter):
package com.example.search.service;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Service;import java.util.List;import java.util.Map;/*** 文档语义搜索服务* 负责把用户问题转成向量,再交给 MySQL 做近邻检索** @authordemo*/@ServicepublicclassDocSearchService {/** JDBC 操作模板 */private final JdbcTemplate jdbcTemplate;/** Embedding 模型客户端,负责把文本转成向量 */private final EmbeddingClient embeddingClient;/*** 构造方法注入依赖** @param jdbcTemplate JDBC 操作模板* @param embeddingClient Embedding 模型客户端*/publicDocSearchService(JdbcTemplate jdbcTemplate, EmbeddingClient embeddingClient) {this.jdbcTemplate = jdbcTemplate;this.embeddingClient = embeddingClient;}/*** 按语义相似度搜索文档** @param question 用户输入的自然语言问题* @param topN 返回条数* @return 文档列表,包含标题、相似度得分和格式化后的创建时间*/publicList> searchBySemantic(String question, int topN) {// 1. 调用模型把问题转成向量,格式形如 [0.01, -0.02, ...]String queryVector = embeddingClient.embedToString(question);// 2. 交给 MySQL 做过滤 + 近邻排序,业务条件和语义排序一次搞定String sql = "SELECT id, title, "+ " DISTANCE(embedding, STRING_TO_VECTOR(?), 'COSINE') AS score, "+ " DATE_FORMAT(create_time, '%Y-%m-%d %H:%i:%s') AS createTimeStr "+ " FROM t_doc "+ " WHERE embedding IS NOT "+ " ORDER BY score ASC "+ " LIMIT ?";return jdbcTemplate.queryForList(sql, queryVector, topN);}}
关键就在于 WHERE 和 ORDER BY 写在了同一条 SQL 里。想加"只搜最近三个月"、"只搜某个分类"这种条件,直接往 WHERE 后面追加即可,不需要在应用层做二次过滤——这是把向量能力放进关系型数据库最直接的收益。
五、要不要升级?一张图帮你决定
新特性看着眼馋,但升级从来不是一句"上吧"就能决定的事。
![]()
几条实践建议:
别跳版本直接升 。从 5.7 到 9.x 中间隔了太多变化,建议先到 8.0/8.4,再往上走。
认证插件是最大的坑 。老版本 JDBC、老 PHP 客户端遇到
caching_sha2_password会直接握手失败,一定要提前压测。Innovation 版有维护窗口 。9.7 出了 9.8,9.7 就不再收补丁了,团队得有跟版节奏的准备。
先用只读副本试水 。把新版本挂成从库,真实流量跑一段时间,观察兼容性和性能再切主。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.